diff --git a/Documentation/DocBook/.gitignore b/Documentation/DocBook/.gitignore index 679034cbd686ceb4e38b8d1879592a132ca4baeb..720f245ceb1f34dcf2f01c9607291db14a118d40 100644 --- a/Documentation/DocBook/.gitignore +++ b/Documentation/DocBook/.gitignore @@ -8,4 +8,7 @@ *.dvi *.log *.out -media/ +*.png +*.gif +media-indices.tmpl +media-entities.tmpl diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 3cebfa0d161182bb562f349359b5676bb660dbd2..66725a3d30dcf5255c31a5428ef177506cec5a0b 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -14,7 +14,9 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \ genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \ 80211.xml debugobjects.xml sh.xml regulator.xml \ alsa-driver-api.xml writing-an-alsa-driver.xml \ - tracepoint.xml media.xml drm.xml + tracepoint.xml drm.xml media_api.xml + +include $(srctree)/Documentation/DocBook/media/Makefile ### # The build process is as follows (targets): @@ -32,7 +34,7 @@ PS_METHOD = $(prefer-db2x) ### # The targets that may be used. -PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs xmldoclinks +PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs BOOKS := $(addprefix $(obj)/,$(DOCBOOKS)) xmldocs: $(BOOKS) @@ -45,27 +47,14 @@ PDF := $(patsubst %.xml, %.pdf, $(BOOKS)) pdfdocs: $(PDF) HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS))) -htmldocs: $(HTML) xmldoclinks +htmldocs: $(HTML) $(call build_main_index) $(call build_images) + $(call install_media_images) MAN := $(patsubst %.xml, %.9, $(BOOKS)) mandocs: $(MAN) -build_images = mkdir -p $(objtree)/Documentation/DocBook/media/ && \ - cp $(srctree)/Documentation/DocBook/dvb/*.png \ - $(srctree)/Documentation/DocBook/v4l/*.gif \ - $(objtree)/Documentation/DocBook/media/ - -xmldoclinks: -ifneq ($(objtree),$(srctree)) - for dep in dvb media-entities.tmpl media-indices.tmpl v4l; do \ - rm -f $(objtree)/Documentation/DocBook/$$dep \ - && ln -s $(srctree)/Documentation/DocBook/$$dep $(objtree)/Documentation/DocBook/ \ - || exit; \ - done -endif - installmandocs: mandocs mkdir -p /usr/local/man/man9/ install Documentation/DocBook/man/*.9.gz /usr/local/man/man9/ @@ -97,11 +86,11 @@ define rule_docproc ) > $(dir $@).$(notdir $@).cmd endef -%.xml: %.tmpl xmldoclinks FORCE +%.xml: %.tmpl FORCE $(call if_changed_rule,docproc) ### -#Read in all saved dependency files +#Read in all saved dependency files cmd_files := $(wildcard $(foreach f,$(BOOKS),$(dir $(f)).$(notdir $(f)).cmd)) ifneq ($(cmd_files),) @@ -150,7 +139,7 @@ quiet_cmd_db2pdf = PDF $@ index = index.html main_idx = Documentation/DocBook/$(index) -build_main_index = rm -rf $(main_idx) && \ +build_main_index = rm -rf $(main_idx); \ echo '

Linux Kernel HTML Documentation

' >> $(main_idx) && \ echo '

Kernel Version: $(KERNELVERSION)

' >> $(main_idx) && \ cat $(HTML) >> $(main_idx) @@ -242,7 +231,7 @@ clean-files := $(DOCBOOKS) \ clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS)) man -cleandocs: +cleandocs: cleanmediadocs $(Q)rm -f $(call objectify, $(clean-files)) $(Q)rm -rf $(call objectify, $(clean-dirs)) diff --git a/Documentation/DocBook/dvb/dvbproperty.xml b/Documentation/DocBook/dvb/dvbproperty.xml deleted file mode 100644 index b5365f61d69b05e8ee4b33e26857927d5fe6b6aa..0000000000000000000000000000000000000000 --- a/Documentation/DocBook/dvb/dvbproperty.xml +++ /dev/null @@ -1,590 +0,0 @@ -
-FE_GET_PROPERTY/FE_SET_PROPERTY - - -/* Reserved fields should be set to 0 */ -struct dtv_property { - __u32 cmd; - union { - __u32 data; - struct { - __u8 data[32]; - __u32 len; - __u32 reserved1[3]; - void *reserved2; - } buffer; - } u; - int result; -} __attribute__ ((packed)); - -/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */ -#define DTV_IOCTL_MAX_MSGS 64 - -struct dtv_properties { - __u32 num; - struct dtv_property *props; -}; - - -
-FE_GET_PROPERTY -DESCRIPTION - - -This ioctl call returns one or more frontend properties. This call only - requires read-only access to the device. - - -SYNOPSIS - - -int ioctl(int fd, int request = FE_GET_PROPERTY, - dtv_properties ⋆props); - - -PARAMETERS - - -int fd - -File descriptor returned by a previous call to open(). - - -int num - -Equals FE_GET_PROPERTY for this command. - - -struct dtv_property *props - -Points to the location where the front-end property commands are stored. - - -ERRORS - - EINVAL - Invalid parameter(s) received or number of parameters out of the range. - - ENOMEM - Out of memory. - - EFAULT - Failure while copying data from/to userspace. - - EOPNOTSUPP - Property type not supported. - -
- -
-FE_SET_PROPERTY -DESCRIPTION - - -This ioctl call sets one or more frontend properties. This call only - requires read-only access to the device. - - -SYNOPSIS - - -int ioctl(int fd, int request = FE_SET_PROPERTY, - dtv_properties ⋆props); - - -PARAMETERS - - -int fd - -File descriptor returned by a previous call to open(). - - -int num - -Equals FE_SET_PROPERTY for this command. - - -struct dtv_property *props - -Points to the location where the front-end property commands are stored. - - -ERRORS - - - EINVAL - Invalid parameter(s) received or number of parameters out of the range. - - ENOMEM - Out of memory. - - EFAULT - Failure while copying data from/to userspace. - - EOPNOTSUPP - Property type not supported. - -
- -
- Property types - -On FE_GET_PROPERTY/FE_SET_PROPERTY, -the actual action is determined by the dtv_property cmd/data pairs. With one single ioctl, is possible to -get/set up to 64 properties. The actual meaning of each property is described on the next sections. - - -The available frontend property types are: - -#define DTV_UNDEFINED 0 -#define DTV_TUNE 1 -#define DTV_CLEAR 2 -#define DTV_FREQUENCY 3 -#define DTV_MODULATION 4 -#define DTV_BANDWIDTH_HZ 5 -#define DTV_INVERSION 6 -#define DTV_DISEQC_MASTER 7 -#define DTV_SYMBOL_RATE 8 -#define DTV_INNER_FEC 9 -#define DTV_VOLTAGE 10 -#define DTV_TONE 11 -#define DTV_PILOT 12 -#define DTV_ROLLOFF 13 -#define DTV_DISEQC_SLAVE_REPLY 14 -#define DTV_FE_CAPABILITY_COUNT 15 -#define DTV_FE_CAPABILITY 16 -#define DTV_DELIVERY_SYSTEM 17 -#define DTV_ISDBT_PARTIAL_RECEPTION 18 -#define DTV_ISDBT_SOUND_BROADCASTING 19 -#define DTV_ISDBT_SB_SUBCHANNEL_ID 20 -#define DTV_ISDBT_SB_SEGMENT_IDX 21 -#define DTV_ISDBT_SB_SEGMENT_COUNT 22 -#define DTV_ISDBT_LAYERA_FEC 23 -#define DTV_ISDBT_LAYERA_MODULATION 24 -#define DTV_ISDBT_LAYERA_SEGMENT_COUNT 25 -#define DTV_ISDBT_LAYERA_TIME_INTERLEAVING 26 -#define DTV_ISDBT_LAYERB_FEC 27 -#define DTV_ISDBT_LAYERB_MODULATION 28 -#define DTV_ISDBT_LAYERB_SEGMENT_COUNT 29 -#define DTV_ISDBT_LAYERB_TIME_INTERLEAVING 30 -#define DTV_ISDBT_LAYERC_FEC 31 -#define DTV_ISDBT_LAYERC_MODULATION 32 -#define DTV_ISDBT_LAYERC_SEGMENT_COUNT 33 -#define DTV_ISDBT_LAYERC_TIME_INTERLEAVING 34 -#define DTV_API_VERSION 35 -#define DTV_CODE_RATE_HP 36 -#define DTV_CODE_RATE_LP 37 -#define DTV_GUARD_INTERVAL 38 -#define DTV_TRANSMISSION_MODE 39 -#define DTV_HIERARCHY 40 -#define DTV_ISDBT_LAYER_ENABLED 41 -#define DTV_ISDBS_TS_ID 42 - -
- -
- Parameters that are common to all Digital TV standards -
- <constant>DTV_FREQUENCY</constant> - - Central frequency of the channel, in HZ. - - Notes: - 1)For ISDB-T, the channels are usually transmitted with an offset of 143kHz. - E.g. a valid frequncy could be 474143 kHz. The stepping is bound to the bandwidth of - the channel which is 6MHz. - - 2)As in ISDB-Tsb the channel consists of only one or three segments the - frequency step is 429kHz, 3*429 respectively. As for ISDB-T the - central frequency of the channel is expected. -
- -
- <constant>DTV_BANDWIDTH_HZ</constant> - - Bandwidth for the channel, in HZ. - - Possible values: - 1712000, - 5000000, - 6000000, - 7000000, - 8000000, - 10000000. - - - Notes: - - 1) For ISDB-T it should be always 6000000Hz (6MHz) - 2) For ISDB-Tsb it can vary depending on the number of connected segments - 3) Bandwidth doesn't apply for DVB-C transmissions, as the bandwidth - for DVB-C depends on the symbol rate - 4) Bandwidth in ISDB-T is fixed (6MHz) or can be easily derived from - other parameters (DTV_ISDBT_SB_SEGMENT_IDX, - DTV_ISDBT_SB_SEGMENT_COUNT). - 5) DVB-T supports 6, 7 and 8MHz. - 6) In addition, DVB-T2 supports 1.172, 5 and 10MHz. -
- -
- <constant>DTV_DELIVERY_SYSTEM</constant> - - Specifies the type of Delivery system - - Possible values: - -typedef enum fe_delivery_system { - SYS_UNDEFINED, - SYS_DVBC_ANNEX_AC, - SYS_DVBC_ANNEX_B, - SYS_DVBT, - SYS_DSS, - SYS_DVBS, - SYS_DVBS2, - SYS_DVBH, - SYS_ISDBT, - SYS_ISDBS, - SYS_ISDBC, - SYS_ATSC, - SYS_ATSCMH, - SYS_DMBTH, - SYS_CMMB, - SYS_DAB, - SYS_DVBT2, -} fe_delivery_system_t; - - -
- -
- <constant>DTV_TRANSMISSION_MODE</constant> - - Specifies the number of carriers used by the standard - - Possible values are: - -typedef enum fe_transmit_mode { - TRANSMISSION_MODE_2K, - TRANSMISSION_MODE_8K, - TRANSMISSION_MODE_AUTO, - TRANSMISSION_MODE_4K, - TRANSMISSION_MODE_1K, - TRANSMISSION_MODE_16K, - TRANSMISSION_MODE_32K, -} fe_transmit_mode_t; - - - Notes: - 1) ISDB-T supports three carrier/symbol-size: 8K, 4K, 2K. It is called - 'mode' in the standard: Mode 1 is 2K, mode 2 is 4K, mode 3 is 8K - - 2) If DTV_TRANSMISSION_MODE is set the TRANSMISSION_MODE_AUTO the - hardware will try to find the correct FFT-size (if capable) and will - use TMCC to fill in the missing parameters. - 3) DVB-T specifies 2K and 8K as valid sizes. - 4) DVB-T2 specifies 1K, 2K, 4K, 8K, 16K and 32K. -
- -
- <constant>DTV_GUARD_INTERVAL</constant> - - Possible values are: - -typedef enum fe_guard_interval { - GUARD_INTERVAL_1_32, - GUARD_INTERVAL_1_16, - GUARD_INTERVAL_1_8, - GUARD_INTERVAL_1_4, - GUARD_INTERVAL_AUTO, - GUARD_INTERVAL_1_128, - GUARD_INTERVAL_19_128, - GUARD_INTERVAL_19_256, -} fe_guard_interval_t; - - - Notes: - 1) If DTV_GUARD_INTERVAL is set the GUARD_INTERVAL_AUTO the hardware will - try to find the correct guard interval (if capable) and will use TMCC to fill - in the missing parameters. - 2) Intervals 1/128, 19/128 and 19/256 are used only for DVB-T2 at present -
-
- -
- ISDB-T frontend - This section describes shortly what are the possible parameters in the Linux - DVB-API called "S2API" and now DVB API 5 in order to tune an ISDB-T/ISDB-Tsb - demodulator: - - This ISDB-T/ISDB-Tsb API extension should reflect all information - needed to tune any ISDB-T/ISDB-Tsb hardware. Of course it is possible - that some very sophisticated devices won't need certain parameters to - tune. - - The information given here should help application writers to know how - to handle ISDB-T and ISDB-Tsb hardware using the Linux DVB-API. - - The details given here about ISDB-T and ISDB-Tsb are just enough to - basically show the dependencies between the needed parameter values, - but surely some information is left out. For more detailed information - see the following documents: - - ARIB STD-B31 - "Transmission System for Digital Terrestrial - Television Broadcasting" and - ARIB TR-B14 - "Operational Guidelines for Digital Terrestrial - Television Broadcasting". - - In order to read this document one has to have some knowledge the - channel structure in ISDB-T and ISDB-Tsb. I.e. it has to be known to - the reader that an ISDB-T channel consists of 13 segments, that it can - have up to 3 layer sharing those segments, and things like that. - - Parameters used by ISDB-T and ISDB-Tsb. - -
- ISDB-T only parameters - -
- <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> - - If DTV_ISDBT_SOUND_BROADCASTING is '0' this bit-field represents whether - the channel is in partial reception mode or not. - - If '1' DTV_ISDBT_LAYERA_* values are assigned to the center segment and - DTV_ISDBT_LAYERA_SEGMENT_COUNT has to be '1'. - - If in addition DTV_ISDBT_SOUND_BROADCASTING is '1' - DTV_ISDBT_PARTIAL_RECEPTION represents whether this ISDB-Tsb channel - is consisting of one segment and layer or three segments and two layers. - - Possible values: 0, 1, -1 (AUTO) -
- -
- <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> - - This field represents whether the other DTV_ISDBT_*-parameters are - referring to an ISDB-T and an ISDB-Tsb channel. (See also - DTV_ISDBT_PARTIAL_RECEPTION). - - Possible values: 0, 1, -1 (AUTO) -
- -
- <constant>DTV_ISDBT_SB_SUBCHANNEL_ID</constant> - - This field only applies if DTV_ISDBT_SOUND_BROADCASTING is '1'. - - (Note of the author: This might not be the correct description of the - SUBCHANNEL-ID in all details, but it is my understanding of the technical - background needed to program a device) - - An ISDB-Tsb channel (1 or 3 segments) can be broadcasted alone or in a - set of connected ISDB-Tsb channels. In this set of channels every - channel can be received independently. The number of connected - ISDB-Tsb segment can vary, e.g. depending on the frequency spectrum - bandwidth available. - - Example: Assume 8 ISDB-Tsb connected segments are broadcasted. The - broadcaster has several possibilities to put those channels in the - air: Assuming a normal 13-segment ISDB-T spectrum he can align the 8 - segments from position 1-8 to 5-13 or anything in between. - - The underlying layer of segments are subchannels: each segment is - consisting of several subchannels with a predefined IDs. A sub-channel - is used to help the demodulator to synchronize on the channel. - - An ISDB-T channel is always centered over all sub-channels. As for - the example above, in ISDB-Tsb it is no longer as simple as that. - - The DTV_ISDBT_SB_SUBCHANNEL_ID parameter is used to give the - sub-channel ID of the segment to be demodulated. - - Possible values: 0 .. 41, -1 (AUTO) -
- -
- - <constant>DTV_ISDBT_SB_SEGMENT_IDX</constant> - - This field only applies if DTV_ISDBT_SOUND_BROADCASTING is '1'. - - DTV_ISDBT_SB_SEGMENT_IDX gives the index of the segment to be - demodulated for an ISDB-Tsb channel where several of them are - transmitted in the connected manner. - - Possible values: 0 .. DTV_ISDBT_SB_SEGMENT_COUNT - 1 - - Note: This value cannot be determined by an automatic channel search. -
- -
- <constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant> - - This field only applies if DTV_ISDBT_SOUND_BROADCASTING is '1'. - - DTV_ISDBT_SB_SEGMENT_COUNT gives the total count of connected ISDB-Tsb - channels. - - Possible values: 1 .. 13 - - Note: This value cannot be determined by an automatic channel search. -
- -
- Hierarchical layers - - ISDB-T channels can be coded hierarchically. As opposed to DVB-T in - ISDB-T hierarchical layers can be decoded simultaneously. For that - reason a ISDB-T demodulator has 3 viterbi and 3 reed-solomon-decoders. - - ISDB-T has 3 hierarchical layers which each can use a part of the - available segments. The total number of segments over all layers has - to 13 in ISDB-T. - -
- <constant>DTV_ISDBT_LAYER_ENABLED</constant> - - Hierarchical reception in ISDB-T is achieved by enabling or disabling - layers in the decoding process. Setting all bits of - DTV_ISDBT_LAYER_ENABLED to '1' forces all layers (if applicable) to be - demodulated. This is the default. - - If the channel is in the partial reception mode - (DTV_ISDBT_PARTIAL_RECEPTION = 1) the central segment can be decoded - independently of the other 12 segments. In that mode layer A has to - have a SEGMENT_COUNT of 1. - - In ISDB-Tsb only layer A is used, it can be 1 or 3 in ISDB-Tsb - according to DTV_ISDBT_PARTIAL_RECEPTION. SEGMENT_COUNT must be filled - accordingly. - - Possible values: 0x1, 0x2, 0x4 (|-able) - - DTV_ISDBT_LAYER_ENABLED[0:0] - layer A - DTV_ISDBT_LAYER_ENABLED[1:1] - layer B - DTV_ISDBT_LAYER_ENABLED[2:2] - layer C - DTV_ISDBT_LAYER_ENABLED[31:3] unused -
- -
- <constant>DTV_ISDBT_LAYER*_FEC</constant> - - Possible values: FEC_AUTO, FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8 -
- -
- <constant>DTV_ISDBT_LAYER*_MODULATION</constant> - - Possible values: QAM_AUTO, QPSK, QAM_16, QAM_64, DQPSK - - Note: If layer C is DQPSK layer B has to be DQPSK. If layer B is DQPSK - and DTV_ISDBT_PARTIAL_RECEPTION=0 layer has to be DQPSK. -
- -
- <constant>DTV_ISDBT_LAYER*_SEGMENT_COUNT</constant> - - Possible values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, -1 (AUTO) - - Note: Truth table for DTV_ISDBT_SOUND_BROADCASTING and - DTV_ISDBT_PARTIAL_RECEPTION and LAYER*_SEGMENT_COUNT - - - - - - - PR - SB - Layer A width - Layer B width - Layer C width - total width - - - - 0 - 0 - 1 .. 13 - 1 .. 13 - 1 .. 13 - 13 - - - - 1 - 0 - 1 - 1 .. 13 - 1 .. 13 - 13 - - - - 0 - 1 - 1 - 0 - 0 - 1 - - - - 1 - 1 - 1 - 2 - 0 - 13 - - - - - - -
- -
- <constant>DTV_ISDBT_LAYER*_TIME_INTERLEAVING</constant> - - Possible values: 0, 1, 2, 3, -1 (AUTO) - - Note: The real inter-leaver depth-names depend on the mode (fft-size); the values - here are referring to what can be found in the TMCC-structure - - independent of the mode. -
-
-
-
- DVB-T2 parameters - - This section covers parameters that apply only to the DVB-T2 delivery method. DVB-T2 - support is currently in the early stages development so expect this section to grow - and become more detailed with time. - -
- <constant>DTV_DVBT2_PLP_ID</constant> - - DVB-T2 supports Physical Layer Pipes (PLP) to allow transmission of - many data types via a single multiplex. The API will soon support this - at which point this section will be expanded. -
-
-
-
diff --git a/Documentation/DocBook/dvb/dvbstb.png b/Documentation/DocBook/dvb/dvbstb.png deleted file mode 100644 index 9b8f372e7afd9d016854973ba705dcdfbd1bbf13..0000000000000000000000000000000000000000 Binary files a/Documentation/DocBook/dvb/dvbstb.png and /dev/null differ diff --git a/Documentation/DocBook/dvb/frontend.h.xml b/Documentation/DocBook/dvb/frontend.h.xml deleted file mode 100644 index d792f789ad3b16f4cc3e67575d601bcae5bbce0a..0000000000000000000000000000000000000000 --- a/Documentation/DocBook/dvb/frontend.h.xml +++ /dev/null @@ -1,428 +0,0 @@ - -/* - * frontend.h - * - * Copyright (C) 2000 Marcus Metzler <marcus@convergence.de> - * Ralph Metzler <ralph@convergence.de> - * Holger Waechtler <holger@convergence.de> - * Andre Draszik <ad@convergence.de> - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * 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 Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef _DVBFRONTEND_H_ -#define _DVBFRONTEND_H_ - -#include <linux/types.h> - -typedef enum fe_type { - FE_QPSK, - FE_QAM, - FE_OFDM, - FE_ATSC -} fe_type_t; - - -typedef enum fe_caps { - FE_IS_STUPID = 0, - FE_CAN_INVERSION_AUTO = 0x1, - FE_CAN_FEC_1_2 = 0x2, - FE_CAN_FEC_2_3 = 0x4, - FE_CAN_FEC_3_4 = 0x8, - FE_CAN_FEC_4_5 = 0x10, - FE_CAN_FEC_5_6 = 0x20, - FE_CAN_FEC_6_7 = 0x40, - FE_CAN_FEC_7_8 = 0x80, - FE_CAN_FEC_8_9 = 0x100, - FE_CAN_FEC_AUTO = 0x200, - FE_CAN_QPSK = 0x400, - FE_CAN_QAM_16 = 0x800, - FE_CAN_QAM_32 = 0x1000, - FE_CAN_QAM_64 = 0x2000, - FE_CAN_QAM_128 = 0x4000, - FE_CAN_QAM_256 = 0x8000, - FE_CAN_QAM_AUTO = 0x10000, - FE_CAN_TRANSMISSION_MODE_AUTO = 0x20000, - FE_CAN_BANDWIDTH_AUTO = 0x40000, - FE_CAN_GUARD_INTERVAL_AUTO = 0x80000, - FE_CAN_HIERARCHY_AUTO = 0x100000, - FE_CAN_8VSB = 0x200000, - FE_CAN_16VSB = 0x400000, - FE_HAS_EXTENDED_CAPS = 0x800000, /* We need more bitspace for newer APIs, indicate this. */ - FE_CAN_TURBO_FEC = 0x8000000, /* frontend supports "turbo fec modulation" */ - FE_CAN_2G_MODULATION = 0x10000000, /* frontend supports "2nd generation modulation" (DVB-S2) */ - FE_NEEDS_BENDING = 0x20000000, /* not supported anymore, don't use (frontend requires frequency bending) */ - FE_CAN_RECOVER = 0x40000000, /* frontend can recover from a cable unplug automatically */ - FE_CAN_MUTE_TS = 0x80000000 /* frontend can stop spurious TS data output */ -} fe_caps_t; - - -struct dvb_frontend_info { - char name[128]; - fe_type_t type; - __u32 frequency_min; - __u32 frequency_max; - __u32 frequency_stepsize; - __u32 frequency_tolerance; - __u32 symbol_rate_min; - __u32 symbol_rate_max; - __u32 symbol_rate_tolerance; /* ppm */ - __u32 notifier_delay; /* DEPRECATED */ - fe_caps_t caps; -}; - - -/** - * Check out the DiSEqC bus spec available on http://www.eutelsat.org/ for - * the meaning of this struct... - */ -struct dvb_diseqc_master_cmd { - __u8 msg [6]; /* { framing, address, command, data [3] } */ - __u8 msg_len; /* valid values are 3...6 */ -}; - - -struct dvb_diseqc_slave_reply { - __u8 msg [4]; /* { framing, data [3] } */ - __u8 msg_len; /* valid values are 0...4, 0 means no msg */ - int timeout; /* return from ioctl after timeout ms with */ -}; /* errorcode when no message was received */ - - -typedef enum fe_sec_voltage { - SEC_VOLTAGE_13, - SEC_VOLTAGE_18, - SEC_VOLTAGE_OFF -} fe_sec_voltage_t; - - -typedef enum fe_sec_tone_mode { - SEC_TONE_ON, - SEC_TONE_OFF -} fe_sec_tone_mode_t; - - -typedef enum fe_sec_mini_cmd { - SEC_MINI_A, - SEC_MINI_B -} fe_sec_mini_cmd_t; - - -typedef enum fe_status { - FE_HAS_SIGNAL = 0x01, /* found something above the noise level */ - FE_HAS_CARRIER = 0x02, /* found a DVB signal */ - FE_HAS_VITERBI = 0x04, /* FEC is stable */ - FE_HAS_SYNC = 0x08, /* found sync bytes */ - FE_HAS_LOCK = 0x10, /* everything's working... */ - FE_TIMEDOUT = 0x20, /* no lock within the last ~2 seconds */ - FE_REINIT = 0x40 /* frontend was reinitialized, */ -} fe_status_t; /* application is recommended to reset */ - /* DiSEqC, tone and parameters */ - -typedef enum fe_spectral_inversion { - INVERSION_OFF, - INVERSION_ON, - INVERSION_AUTO -} fe_spectral_inversion_t; - - -typedef enum fe_code_rate { - FEC_NONE = 0, - FEC_1_2, - FEC_2_3, - FEC_3_4, - FEC_4_5, - FEC_5_6, - FEC_6_7, - FEC_7_8, - FEC_8_9, - FEC_AUTO, - FEC_3_5, - FEC_9_10, -} fe_code_rate_t; - - -typedef enum fe_modulation { - QPSK, - QAM_16, - QAM_32, - QAM_64, - QAM_128, - QAM_256, - QAM_AUTO, - VSB_8, - VSB_16, - PSK_8, - APSK_16, - APSK_32, - DQPSK, -} fe_modulation_t; - -typedef enum fe_transmit_mode { - TRANSMISSION_MODE_2K, - TRANSMISSION_MODE_8K, - TRANSMISSION_MODE_AUTO, - TRANSMISSION_MODE_4K, - TRANSMISSION_MODE_1K, - TRANSMISSION_MODE_16K, - TRANSMISSION_MODE_32K, -} fe_transmit_mode_t; - -typedef enum fe_bandwidth { - BANDWIDTH_8_MHZ, - BANDWIDTH_7_MHZ, - BANDWIDTH_6_MHZ, - BANDWIDTH_AUTO, - BANDWIDTH_5_MHZ, - BANDWIDTH_10_MHZ, - BANDWIDTH_1_712_MHZ, -} fe_bandwidth_t; - - -typedef enum fe_guard_interval { - GUARD_INTERVAL_1_32, - GUARD_INTERVAL_1_16, - GUARD_INTERVAL_1_8, - GUARD_INTERVAL_1_4, - GUARD_INTERVAL_AUTO, - GUARD_INTERVAL_1_128, - GUARD_INTERVAL_19_128, - GUARD_INTERVAL_19_256, -} fe_guard_interval_t; - - -typedef enum fe_hierarchy { - HIERARCHY_NONE, - HIERARCHY_1, - HIERARCHY_2, - HIERARCHY_4, - HIERARCHY_AUTO -} fe_hierarchy_t; - - -struct dvb_qpsk_parameters { - __u32 symbol_rate; /* symbol rate in Symbols per second */ - fe_code_rate_t fec_inner; /* forward error correction (see above) */ -}; - -struct dvb_qam_parameters { - __u32 symbol_rate; /* symbol rate in Symbols per second */ - fe_code_rate_t fec_inner; /* forward error correction (see above) */ - fe_modulation_t modulation; /* modulation type (see above) */ -}; - -struct dvb_vsb_parameters { - fe_modulation_t modulation; /* modulation type (see above) */ -}; - -struct dvb_ofdm_parameters { - fe_bandwidth_t bandwidth; - fe_code_rate_t code_rate_HP; /* high priority stream code rate */ - fe_code_rate_t code_rate_LP; /* low priority stream code rate */ - fe_modulation_t constellation; /* modulation type (see above) */ - fe_transmit_mode_t transmission_mode; - fe_guard_interval_t guard_interval; - fe_hierarchy_t hierarchy_information; -}; - - -struct dvb_frontend_parameters { - __u32 frequency; /* (absolute) frequency in Hz for QAM/OFDM/ATSC */ - /* intermediate frequency in kHz for QPSK */ - fe_spectral_inversion_t inversion; - union { - struct dvb_qpsk_parameters qpsk; - struct dvb_qam_parameters qam; - struct dvb_ofdm_parameters ofdm; - struct dvb_vsb_parameters vsb; - } u; -}; - - -struct dvb_frontend_event { - fe_status_t status; - struct dvb_frontend_parameters parameters; -}; - -/* S2API Commands */ -#define DTV_UNDEFINED 0 -#define DTV_TUNE 1 -#define DTV_CLEAR 2 -#define DTV_FREQUENCY 3 -#define DTV_MODULATION 4 -#define DTV_BANDWIDTH_HZ 5 -#define DTV_INVERSION 6 -#define DTV_DISEQC_MASTER 7 -#define DTV_SYMBOL_RATE 8 -#define DTV_INNER_FEC 9 -#define DTV_VOLTAGE 10 -#define DTV_TONE 11 -#define DTV_PILOT 12 -#define DTV_ROLLOFF 13 -#define DTV_DISEQC_SLAVE_REPLY 14 - -/* Basic enumeration set for querying unlimited capabilities */ -#define DTV_FE_CAPABILITY_COUNT 15 -#define DTV_FE_CAPABILITY 16 -#define DTV_DELIVERY_SYSTEM 17 - -/* ISDB-T and ISDB-Tsb */ -#define DTV_ISDBT_PARTIAL_RECEPTION 18 -#define DTV_ISDBT_SOUND_BROADCASTING 19 - -#define DTV_ISDBT_SB_SUBCHANNEL_ID 20 -#define DTV_ISDBT_SB_SEGMENT_IDX 21 -#define DTV_ISDBT_SB_SEGMENT_COUNT 22 - -#define DTV_ISDBT_LAYERA_FEC 23 -#define DTV_ISDBT_LAYERA_MODULATION 24 -#define DTV_ISDBT_LAYERA_SEGMENT_COUNT 25 -#define DTV_ISDBT_LAYERA_TIME_INTERLEAVING 26 - -#define DTV_ISDBT_LAYERB_FEC 27 -#define DTV_ISDBT_LAYERB_MODULATION 28 -#define DTV_ISDBT_LAYERB_SEGMENT_COUNT 29 -#define DTV_ISDBT_LAYERB_TIME_INTERLEAVING 30 - -#define DTV_ISDBT_LAYERC_FEC 31 -#define DTV_ISDBT_LAYERC_MODULATION 32 -#define DTV_ISDBT_LAYERC_SEGMENT_COUNT 33 -#define DTV_ISDBT_LAYERC_TIME_INTERLEAVING 34 - -#define DTV_API_VERSION 35 - -#define DTV_CODE_RATE_HP 36 -#define DTV_CODE_RATE_LP 37 -#define DTV_GUARD_INTERVAL 38 -#define DTV_TRANSMISSION_MODE 39 -#define DTV_HIERARCHY 40 - -#define DTV_ISDBT_LAYER_ENABLED 41 - -#define DTV_ISDBS_TS_ID 42 - -#define DTV_DVBT2_PLP_ID 43 - -#define DTV_MAX_COMMAND DTV_DVBT2_PLP_ID - -typedef enum fe_pilot { - PILOT_ON, - PILOT_OFF, - PILOT_AUTO, -} fe_pilot_t; - -typedef enum fe_rolloff { - ROLLOFF_35, /* Implied value in DVB-S, default for DVB-S2 */ - ROLLOFF_20, - ROLLOFF_25, - ROLLOFF_AUTO, -} fe_rolloff_t; - -typedef enum fe_delivery_system { - SYS_UNDEFINED, - SYS_DVBC_ANNEX_AC, - SYS_DVBC_ANNEX_B, - SYS_DVBT, - SYS_DSS, - SYS_DVBS, - SYS_DVBS2, - SYS_DVBH, - SYS_ISDBT, - SYS_ISDBS, - SYS_ISDBC, - SYS_ATSC, - SYS_ATSCMH, - SYS_DMBTH, - SYS_CMMB, - SYS_DAB, - SYS_DVBT2, -} fe_delivery_system_t; - -struct dtv_cmds_h { - char *name; /* A display name for debugging purposes */ - - __u32 cmd; /* A unique ID */ - - /* Flags */ - __u32 set:1; /* Either a set or get property */ - __u32 buffer:1; /* Does this property use the buffer? */ - __u32 reserved:30; /* Align */ -}; - -struct dtv_property { - __u32 cmd; - __u32 reserved[3]; - union { - __u32 data; - struct { - __u8 data[32]; - __u32 len; - __u32 reserved1[3]; - void *reserved2; - } buffer; - } u; - int result; -} __attribute__ ((packed)); - -/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */ -#define DTV_IOCTL_MAX_MSGS 64 - -struct dtv_properties { - __u32 num; - struct dtv_property *props; -}; - -#define FE_SET_PROPERTY _IOW('o', 82, struct dtv_properties) -#define FE_GET_PROPERTY _IOR('o', 83, struct dtv_properties) - - -/** - * When set, this flag will disable any zigzagging or other "normal" tuning - * behaviour. Additionally, there will be no automatic monitoring of the lock - * status, and hence no frontend events will be generated. If a frontend device - * is closed, this flag will be automatically turned off when the device is - * reopened read-write. - */ -#define FE_TUNE_MODE_ONESHOT 0x01 - - -#define FE_GET_INFO _IOR('o', 61, struct dvb_frontend_info) - -#define FE_DISEQC_RESET_OVERLOAD _IO('o', 62) -#define FE_DISEQC_SEND_MASTER_CMD _IOW('o', 63, struct dvb_diseqc_master_cmd) -#define FE_DISEQC_RECV_SLAVE_REPLY _IOR('o', 64, struct dvb_diseqc_slave_reply) -#define FE_DISEQC_SEND_BURST _IO('o', 65) /* fe_sec_mini_cmd_t */ - -#define FE_SET_TONE _IO('o', 66) /* fe_sec_tone_mode_t */ -#define FE_SET_VOLTAGE _IO('o', 67) /* fe_sec_voltage_t */ -#define FE_ENABLE_HIGH_LNB_VOLTAGE _IO('o', 68) /* int */ - -#define FE_READ_STATUS _IOR('o', 69, fe_status_t) -#define FE_READ_BER _IOR('o', 70, __u32) -#define FE_READ_SIGNAL_STRENGTH _IOR('o', 71, __u16) -#define FE_READ_SNR _IOR('o', 72, __u16) -#define FE_READ_UNCORRECTED_BLOCKS _IOR('o', 73, __u32) - -#define FE_SET_FRONTEND _IOW('o', 76, struct dvb_frontend_parameters) -#define FE_GET_FRONTEND _IOR('o', 77, struct dvb_frontend_parameters) -#define FE_SET_FRONTEND_TUNE_MODE _IO('o', 81) /* unsigned int */ -#define FE_GET_EVENT _IOR('o', 78, struct dvb_frontend_event) - -#define FE_DISHNETWORK_SEND_LEGACY_CMD _IO('o', 80) /* unsigned int */ - -#endif /*_DVBFRONTEND_H_*/ - diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl deleted file mode 100644 index e5fe09430fd905c19fa04f0d1d401f5f76bd9f2c..0000000000000000000000000000000000000000 --- a/Documentation/DocBook/media-entities.tmpl +++ /dev/null @@ -1,464 +0,0 @@ - - - -close()"> -ioctl()"> -mmap()"> -munmap()"> -open()"> -poll()"> -read()"> -select()"> -write()"> - -close()"> -ioctl()"> -open()"> - - -VIDIOC_CROPCAP"> -VIDIOC_DBG_G_CHIP_IDENT"> -VIDIOC_DBG_G_REGISTER"> -VIDIOC_DBG_S_REGISTER"> -VIDIOC_DQBUF"> -VIDIOC_DQEVENT"> -VIDIOC_ENCODER_CMD"> -VIDIOC_ENUMAUDIO"> -VIDIOC_ENUMAUDOUT"> -VIDIOC_ENUMINPUT"> -VIDIOC_ENUMOUTPUT"> -VIDIOC_ENUMSTD"> -VIDIOC_ENUM_DV_PRESETS"> -VIDIOC_ENUM_FMT"> -VIDIOC_ENUM_FRAMEINTERVALS"> -VIDIOC_ENUM_FRAMESIZES"> -VIDIOC_G_AUDIO"> -VIDIOC_G_AUDOUT"> -VIDIOC_G_CROP"> -VIDIOC_G_CTRL"> -VIDIOC_G_DV_PRESET"> -VIDIOC_G_DV_TIMINGS"> -VIDIOC_G_ENC_INDEX"> -VIDIOC_G_EXT_CTRLS"> -VIDIOC_G_FBUF"> -VIDIOC_G_FMT"> -VIDIOC_G_FREQUENCY"> -VIDIOC_G_INPUT"> -VIDIOC_G_JPEGCOMP"> -VIDIOC_G_MPEGCOMP"> -VIDIOC_G_MODULATOR"> -VIDIOC_G_OUTPUT"> -VIDIOC_G_PARM"> -VIDIOC_G_PRIORITY"> -VIDIOC_G_SLICED_VBI_CAP"> -VIDIOC_G_STD"> -VIDIOC_G_TUNER"> -VIDIOC_LOG_STATUS"> -VIDIOC_OVERLAY"> -VIDIOC_QBUF"> -VIDIOC_QUERYBUF"> -VIDIOC_QUERYCAP"> -VIDIOC_QUERYCTRL"> -VIDIOC_QUERYMENU"> -VIDIOC_QUERYSTD"> -VIDIOC_QUERY_DV_PRESET"> -VIDIOC_REQBUFS"> -VIDIOC_STREAMOFF"> -VIDIOC_STREAMON"> -VIDIOC_SUBSCRIBE_EVENT"> -VIDIOC_S_AUDIO"> -VIDIOC_S_AUDOUT"> -VIDIOC_S_CROP"> -VIDIOC_S_CTRL"> -VIDIOC_S_DV_PRESET"> -VIDIOC_S_DV_TIMINGS"> -VIDIOC_S_EXT_CTRLS"> -VIDIOC_S_FBUF"> -VIDIOC_S_FMT"> -VIDIOC_S_FREQUENCY"> -VIDIOC_S_HW_FREQ_SEEK"> -VIDIOC_S_INPUT"> -VIDIOC_S_JPEGCOMP"> -VIDIOC_S_MPEGCOMP"> -VIDIOC_S_MODULATOR"> -VIDIOC_S_OUTPUT"> -VIDIOC_S_PARM"> -VIDIOC_S_PRIORITY"> -VIDIOC_S_STD"> -VIDIOC_S_TUNER"> -VIDIOC_SUBDEV_ENUM_FRAME_SIZE"> -VIDIOC_SUBDEV_ENUM_MBUS_CODE"> -VIDIOC_SUBDEV_G_CROP"> -VIDIOC_SUBDEV_G_FMT"> -VIDIOC_SUBDEV_G_FRAME_INTERVAL"> -VIDIOC_SUBDEV_S_CROP"> -VIDIOC_SUBDEV_S_FMT"> -VIDIOC_SUBDEV_S_FRAME_INTERVAL"> -VIDIOC_TRY_ENCODER_CMD"> -VIDIOC_TRY_EXT_CTRLS"> -VIDIOC_TRY_FMT"> -VIDIOC_UNSUBSCRIBE_EVENT"> - -MEDIA_IOC_DEVICE_INFO"> -MEDIA_IOC_ENUM_ENTITIES"> -MEDIA_IOC_ENUM_LINKS"> -MEDIA_IOC_SETUP_LINK"> - - -v4l2_std_id"> - - -v4l2_buf_type"> -v4l2_colorspace"> -v4l2_ctrl_type"> -v4l2_exposure_auto_type"> -v4l2_field"> -v4l2_frmivaltypes"> -v4l2_frmsizetypes"> -v4l2_mbus_pixelcode"> -v4l2_memory"> -v4l2_mpeg_audio_ac3_bitrate"> -v4l2_mpeg_audio_crc"> -v4l2_mpeg_audio_emphasis"> -v4l2_mpeg_audio_encoding"> -v4l2_mpeg_audio_l1_bitrate"> -v4l2_mpeg_audio_l2_bitrate"> -v4l2_mpeg_audio_l3_bitrate"> -v4l2_mpeg_audio_mode"> -v4l2_mpeg_audio_mode_extension"> -v4l2_mpeg_audio_sampling_freq"> -v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type"> -v4l2_mpeg_cx2341x_video_luma_spatial_filter_type"> -v4l2_mpeg_cx2341x_video_median_filter_type"> -v4l2_mpeg_cx2341x_video_spatial_filter_mode"> -v4l2_mpeg_cx2341x_video_temporal_filter_mode"> -v4l2_mpeg_stream_type"> -v4l2_mpeg_stream_vbi_fmt"> -v4l2_mpeg_video_aspect"> -v4l2_mpeg_video_bitrate_mode"> -v4l2_mpeg_video_encoding"> -v4l2_power_line_frequency"> -v4l2_priority"> -v4l2_subdev_format_whence"> -v4l2_tuner_type"> -v4l2_preemphasis"> - - -v4l2_audio"> -v4l2_audioout"> -v4l2_bt_timings"> -v4l2_buffer"> -v4l2_plane"> -v4l2_capability"> -v4l2_captureparm"> -v4l2_clip"> -v4l2_control"> -v4l2_crop"> -v4l2_cropcap"> -v4l2_dbg_chip_ident"> -v4l2_dbg_match"> -v4l2_dbg_register"> -v4l2_dv_enum_preset"> -v4l2_dv_preset"> -v4l2_dv_timings"> -v4l2_enc_idx"> -v4l2_enc_idx_entry"> -v4l2_encoder_cmd"> -v4l2_event"> -v4l2_event_subscription"> -v4l2_event_vsync"> -v4l2_ext_control"> -v4l2_ext_controls"> -v4l2_fmtdesc"> -v4l2_format"> -v4l2_fract"> -v4l2_framebuffer"> -v4l2_frequency"> -v4l2_frmival_stepwise"> -v4l2_frmivalenum"> -v4l2_frmsize_discrete"> -v4l2_frmsize_stepwise"> -v4l2_frmsizeenum"> -v4l2_hw_freq_seek"> -v4l2_input"> -v4l2_jpegcompression"> -v4l2_mbus_framefmt"> -v4l2_modulator"> -v4l2_mpeg_vbi_fmt_ivtv"> -v4l2_output"> -v4l2_outputparm"> -v4l2_pix_format"> -v4l2_pix_format_mplane"> -v4l2_plane_pix_format"> -v4l2_queryctrl"> -v4l2_querymenu"> -v4l2_rect"> -v4l2_requestbuffers"> -v4l2_sliced_vbi_cap"> -v4l2_sliced_vbi_data"> -v4l2_sliced_vbi_format"> -v4l2_subdev_frame_interval"> -v4l2_subdev_frame_interval_enum"> -v4l2_subdev_frame_size_enum"> -v4l2_subdev_crop"> -v4l2_subdev_format"> -v4l2_subdev_mbus_code_enum"> -v4l2_standard"> -v4l2_streamparm"> -v4l2_timecode"> -v4l2_tuner"> -v4l2_vbi_format"> -v4l2_window"> - -media_device_info"> -media_entity_desc"> -media_links_enum"> -media_pad_desc"> -media_link_desc"> - - -EACCES error code"> -EAGAIN error code"> -EBADF error code"> -EBUSY error code"> -EFAULT error code"> -EIO error code"> -EINTR error code"> -EINVAL error code"> -ENFILE error code"> -ENOMEM error code"> -ENOSPC error code"> -ENOTTY error code"> -ENXIO error code"> -EMFILE error code"> -EPERM error code"> -EPIPE error code"> -ERANGE error code"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Documentation/DocBook/media-indices.tmpl b/Documentation/DocBook/media-indices.tmpl deleted file mode 100644 index 78d6031de001bc5fd46a926c91037058e85aa3ff..0000000000000000000000000000000000000000 --- a/Documentation/DocBook/media-indices.tmpl +++ /dev/null @@ -1,89 +0,0 @@ - - -List of Types -v4l2_std_id -enum v4l2_buf_type -enum v4l2_colorspace -enum v4l2_ctrl_type -enum v4l2_exposure_auto_type -enum v4l2_field -enum v4l2_frmivaltypes -enum v4l2_frmsizetypes -enum v4l2_memory -enum v4l2_mpeg_audio_ac3_bitrate -enum v4l2_mpeg_audio_crc -enum v4l2_mpeg_audio_emphasis -enum v4l2_mpeg_audio_encoding -enum v4l2_mpeg_audio_l1_bitrate -enum v4l2_mpeg_audio_l2_bitrate -enum v4l2_mpeg_audio_l3_bitrate -enum v4l2_mpeg_audio_mode -enum v4l2_mpeg_audio_mode_extension -enum v4l2_mpeg_audio_sampling_freq -enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type -enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type -enum v4l2_mpeg_cx2341x_video_median_filter_type -enum v4l2_mpeg_cx2341x_video_spatial_filter_mode -enum v4l2_mpeg_cx2341x_video_temporal_filter_mode -enum v4l2_mpeg_stream_type -enum v4l2_mpeg_stream_vbi_fmt -enum v4l2_mpeg_video_aspect -enum v4l2_mpeg_video_bitrate_mode -enum v4l2_mpeg_video_encoding -enum v4l2_power_line_frequency -enum v4l2_priority -enum v4l2_tuner_type -enum v4l2_preemphasis -struct v4l2_audio -struct v4l2_audioout -struct v4l2_bt_timings -struct v4l2_buffer -struct v4l2_capability -struct v4l2_captureparm -struct v4l2_clip -struct v4l2_control -struct v4l2_crop -struct v4l2_cropcap -struct v4l2_dbg_chip_ident -struct v4l2_dbg_match -struct v4l2_dbg_register -struct v4l2_dv_enum_preset -struct v4l2_dv_preset -struct v4l2_dv_timings -struct v4l2_enc_idx -struct v4l2_enc_idx_entry -struct v4l2_encoder_cmd -struct v4l2_ext_control -struct v4l2_ext_controls -struct v4l2_fmtdesc -struct v4l2_format -struct v4l2_fract -struct v4l2_framebuffer -struct v4l2_frequency -struct v4l2_frmival_stepwise -struct v4l2_frmivalenum -struct v4l2_frmsize_discrete -struct v4l2_frmsize_stepwise -struct v4l2_frmsizeenum -struct v4l2_hw_freq_seek -struct v4l2_input -struct v4l2_jpegcompression -struct v4l2_modulator -struct v4l2_mpeg_vbi_fmt_ivtv -struct v4l2_output -struct v4l2_outputparm -struct v4l2_pix_format -struct v4l2_queryctrl -struct v4l2_querymenu -struct v4l2_rect -struct v4l2_requestbuffers -struct v4l2_sliced_vbi_cap -struct v4l2_sliced_vbi_data -struct v4l2_sliced_vbi_format -struct v4l2_standard -struct v4l2_streamparm -struct v4l2_timecode -struct v4l2_tuner -struct v4l2_vbi_format -struct v4l2_window - diff --git a/Documentation/DocBook/media/Makefile b/Documentation/DocBook/media/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6628b4b9cac49fb13ed96776ac9259f97e08d71d --- /dev/null +++ b/Documentation/DocBook/media/Makefile @@ -0,0 +1,386 @@ +### +# Media build rules - Auto-generates media contents/indexes and *.h xml's +# + +SHELL=/bin/bash + +MEDIA_OBJ_DIR=$(objtree)/Documentation/DocBook/ +MEDIA_SRC_DIR=$(srctree)/Documentation/DocBook/media + +MEDIA_TEMP = media-entities.tmpl \ + media-indices.tmpl \ + videodev2.h.xml \ + v4l2.xml \ + audio.h.xml \ + ca.h.xml \ + dmx.h.xml \ + frontend.h.xml \ + net.h.xml \ + video.h.xml \ + +IMGFILES := $(patsubst %.b64,%, $(notdir $(shell ls $(MEDIA_SRC_DIR)/*.b64))) +OBJIMGFILES := $(addprefix $(MEDIA_OBJ_DIR)/, $(IMGFILES)) +GENFILES := $(addprefix $(MEDIA_OBJ_DIR)/, $(MEDIA_TEMP)) + +PHONY += cleanmediadocs + +cleanmediadocs: + -@rm `find $(MEDIA_OBJ_DIR) -type l` $(GENFILES) $(OBJIMGFILES) 2>/dev/null + +$(obj)/media_api.xml: $(GENFILES) FORCE + +#$(MEDIA_OBJ_DIR)/media_api.html: $(MEDIA_OBJ_DIR)/media_api.xml +#$(MEDIA_OBJ_DIR)/media_api.pdf: $(MEDIA_OBJ_DIR)/media_api.xml +#$(MEDIA_OBJ_DIR)/media_api.ps: $(MEDIA_OBJ_DIR)/media_api.xml + +V4L_SGMLS = \ + $(shell ls $(MEDIA_SRC_DIR)/v4l/*.xml|perl -ne 'print "$$1 " if (m,.*/(.*)\n,)') \ + capture.c.xml \ + keytable.c.xml \ + v4l2grab.c.xml + +DVB_SGMLS = \ + $(shell ls $(MEDIA_SRC_DIR)/dvb/*.xml|perl -ne 'print "$$1 " if (m,.*/(.*)\n,)') + +MEDIA_SGMLS = $(addprefix ./,$(V4L_SGMLS)) $(addprefix ./,$(DVB_SGMLS)) $(addprefix ./,$(MEDIA_TEMP)) + +FUNCS = \ + close \ + ioctl \ + mmap \ + munmap \ + open \ + poll \ + read \ + select \ + write \ + +IOCTLS = \ + $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/videodev2.h) \ + $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/audio.h) \ + $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/ca.h) \ + $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/dmx.h) \ + $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/frontend.h) \ + $(shell perl -ne 'print "$$1 " if /\#define\s+([A-Z][^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/net.h) \ + $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/video.h) \ + $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/media.h) \ + $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/v4l2-subdev.h) \ + VIDIOC_SUBDEV_G_FRAME_INTERVAL \ + VIDIOC_SUBDEV_S_FRAME_INTERVAL \ + VIDIOC_SUBDEV_ENUM_MBUS_CODE \ + VIDIOC_SUBDEV_ENUM_FRAME_SIZE \ + VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL \ + +TYPES = \ + $(shell perl -ne 'print "$$1 " if /^typedef\s+[^\s]+\s+([^\s]+)\;/' $(srctree)/include/linux/videodev2.h) \ + $(shell perl -ne 'print "$$1 " if /^}\s+([a-z0-9_]+_t)/' $(srctree)/include/linux/dvb/frontend.h) + +ENUMS = \ + $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/videodev2.h) \ + $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/audio.h) \ + $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/ca.h) \ + $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/dmx.h) \ + $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/frontend.h) \ + $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/net.h) \ + $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/video.h) \ + $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/media.h) \ + $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/v4l2-mediabus.h) \ + $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/v4l2-subdev.h) + +STRUCTS = \ + $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/linux/videodev2.h) \ + $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s\{]+)\s*/)' $(srctree)/include/linux/dvb/audio.h) \ + $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/linux/dvb/ca.h) \ + $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/linux/dvb/dmx.h) \ + $(shell perl -ne 'print "$$1 " if (!/dtv\_cmds\_h/ && /^struct\s+([^\s]+)\s+/)' $(srctree)/include/linux/dvb/frontend.h) \ + $(shell perl -ne 'print "$$1 " if (/^struct\s+([A-Z][^\s]+)\s+/)' $(srctree)/include/linux/dvb/net.h) \ + $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/linux/dvb/video.h) \ + $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/linux/media.h) \ + $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/linux/v4l2-subdev.h) \ + $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/linux/v4l2-mediabus.h) + +ERRORS = \ + E2BIG \ + EACCES \ + EAGAIN \ + EBADF \ + EBADFD \ + EBADR \ + EBADRQC \ + EBUSY \ + ECHILD \ + ECONNRESET \ + EDEADLK \ + EDOM \ + EEXIST \ + EFAULT \ + EFBIG \ + EILSEQ \ + EINIT \ + EINPROGRESS \ + EINTR \ + EINVAL \ + EIO \ + EMFILE \ + ENFILE \ + ENOBUFS \ + ENODATA \ + ENODEV \ + ENOENT \ + ENOIOCTLCMD \ + ENOMEM \ + ENOSPC \ + ENOSR \ + ENOSYS \ + ENOTSUP \ + ENOTSUPP \ + ENOTTY \ + ENXIO \ + EOPNOTSUPP \ + EOVERFLOW \ + EPERM \ + EPIPE \ + EPROTO \ + ERANGE \ + EREMOTE \ + EREMOTEIO \ + ERESTART \ + ERESTARTSYS \ + ESHUTDOWN \ + ESPIPE \ + ETIME \ + ETIMEDOUT \ + EUSERS \ + EWOULDBLOCK \ + EXDEV \ + +ESCAPE = \ + -e "s/&/\\&/g" \ + -e "s//\\>/g" + +FILENAME = \ + -e s,"^[^\/]*/",, \ + -e s/"\\.xml"// \ + -e s/"\\.tmpl"// \ + -e s/\\\./-/g \ + -e s/"^func-"// \ + -e s/"^pixfmt-"// \ + -e s/"^vidioc-"// + +# Generate references to these structs in videodev2.h.xml. +DOCUMENTED = \ + -e "s/\(enum *\)v4l2_mpeg_cx2341x_video_\([a-z]*_spatial_filter_type\)/\1v4l2_mpeg_cx2341x_video_\2<\/link>/g" \ + -e "s/\(\(enum\|struct\) *\)\(v4l2_[a-zA-Z0-9_]*\)/\1\3<\/link>/g" \ + -e "s/\(V4L2_PIX_FMT_[A-Z0-9_]\+\) /\1<\/link> /g" \ + -e ":a;s/\(linkend=\".*\)_\(.*\">\)/\1-\2/;ta" \ + -e "s/v4l2\-mpeg\-vbi\-ITV0/v4l2-mpeg-vbi-itv0-1/g" + +DVB_DOCUMENTED = \ + -e "s/\(linkend\=\"\)FE_SET_PROPERTY/\1FE_GET_PROPERTY/g" \ + -e "s,\(struct\s\+\)\([a-z0-9_]\+\)\(\s\+{\),\1\\2\<\/link\>\3,g" \ + -e "s,\(}\s\+\)\([a-z0-9_]\+_t\+\),\1\\2\<\/link\>,g" \ + -e "s,\(define\s\+\)\(DTV_[A-Z0-9_]\+\)\(\s\+[0-9]\+\),\1\\2\<\/link\>\3,g" \ + -e "s,\(DTV_IOCTL_MAX_MSGS\|dtv_cmds_h\|__.*_old\)<\/link>,\1,g" \ + -e ":a;s/\(linkend=\".*\)_\(.*\">\)/\1-\2/;ta" \ + -e "s,\(audio-mixer\|audio-karaoke\|audio-status\|ca-slot-info\|ca-descr-info\|ca-caps\|ca-msg\|ca-descr\|ca-pid\|dmx-filter\|dmx-caps\|video-system\|video-highlight\|video-spu\|video-spu-palette\|video-navi-pack\)-t,\1,g" \ + -e "s,DTV-ISDBT-LAYER[A-C],DTV-ISDBT-LAYER,g" \ + -e "s,\(define\s\+\)\([A-Z0-9_]\+\)\(\s\+_IO\),\1\\2\<\/link\>\3,g" \ + -e "s,\(__.*_OLD\)<\/link>,\1,g" \ + +# +# Media targets and dependencies +# + +install_media_images = \ + $(Q)cp $(OBJIMGFILES) $(MEDIA_OBJ_DIR)/media_api + +$(MEDIA_OBJ_DIR)/%: $(MEDIA_SRC_DIR)/%.b64 + $(Q)base64 -d $< >$@ + +$(MEDIA_OBJ_DIR)/v4l2.xml: $(OBJIMGFILES) + @$($(quiet)gen_xml) + @(ln -sf $(MEDIA_SRC_DIR)/v4l/*xml $(MEDIA_OBJ_DIR)/) + @(ln -sf $(MEDIA_SRC_DIR)/dvb/*xml $(MEDIA_OBJ_DIR)/) + +$(MEDIA_OBJ_DIR)/videodev2.h.xml: $(srctree)/include/linux/videodev2.h $(MEDIA_OBJ_DIR)/v4l2.xml + @$($(quiet)gen_xml) + @( \ + echo "") > $@ + @( \ + expand --tabs=8 < $< | \ + sed $(ESCAPE) $(DOCUMENTED) | \ + sed 's/i\.e\./&ie;/') >> $@ + @( \ + echo "") >> $@ + +$(MEDIA_OBJ_DIR)/audio.h.xml: $(srctree)/include/linux/dvb/audio.h $(MEDIA_OBJ_DIR)/v4l2.xml + @$($(quiet)gen_xml) + @( \ + echo "") > $@ + @( \ + expand --tabs=8 < $< | \ + sed $(ESCAPE) $(DVB_DOCUMENTED) | \ + sed 's/i\.e\./&ie;/') >> $@ + @( \ + echo "") >> $@ + +$(MEDIA_OBJ_DIR)/ca.h.xml: $(srctree)/include/linux/dvb/ca.h $(MEDIA_OBJ_DIR)/v4l2.xml + @$($(quiet)gen_xml) + @( \ + echo "") > $@ + @( \ + expand --tabs=8 < $< | \ + sed $(ESCAPE) $(DVB_DOCUMENTED) | \ + sed 's/i\.e\./&ie;/') >> $@ + @( \ + echo "") >> $@ + +$(MEDIA_OBJ_DIR)/dmx.h.xml: $(srctree)/include/linux/dvb/dmx.h $(MEDIA_OBJ_DIR)/v4l2.xml + @$($(quiet)gen_xml) + @( \ + echo "") > $@ + @( \ + expand --tabs=8 < $< | \ + sed $(ESCAPE) $(DVB_DOCUMENTED) | \ + sed 's/i\.e\./&ie;/') >> $@ + @( \ + echo "") >> $@ + +$(MEDIA_OBJ_DIR)/frontend.h.xml: $(srctree)/include/linux/dvb/frontend.h $(MEDIA_OBJ_DIR)/v4l2.xml + @$($(quiet)gen_xml) + @( \ + echo "") > $@ + @( \ + expand --tabs=8 < $< | \ + sed $(ESCAPE) $(DVB_DOCUMENTED) | \ + sed 's/i\.e\./&ie;/') >> $@ + @( \ + echo "") >> $@ + +$(MEDIA_OBJ_DIR)/net.h.xml: $(srctree)/include/linux/dvb/net.h $(MEDIA_OBJ_DIR)/v4l2.xml + @$($(quiet)gen_xml) + @( \ + echo "") > $@ + @( \ + expand --tabs=8 < $< | \ + sed $(ESCAPE) $(DVB_DOCUMENTED) | \ + sed 's/i\.e\./&ie;/') >> $@ + @( \ + echo "") >> $@ + +$(MEDIA_OBJ_DIR)/video.h.xml: $(srctree)/include/linux/dvb/video.h $(MEDIA_OBJ_DIR)/v4l2.xml + @$($(quiet)gen_xml) + @( \ + echo "") > $@ + @( \ + expand --tabs=8 < $< | \ + sed $(ESCAPE) $(DVB_DOCUMENTED) | \ + sed 's/i\.e\./&ie;/') >> $@ + @( \ + echo "") >> $@ + +$(MEDIA_OBJ_DIR)/media-entities.tmpl: $(MEDIA_OBJ_DIR)/v4l2.xml + @$($(quiet)gen_xml) + @( \ + echo "") >$@ + @( \ + echo -e "\n") >>$@ + @( \ + for ident in $(FUNCS) ; do \ + entity=`echo $$ident | tr _ -` ; \ + echo "$$ident()\">" \ + >>$@ ; \ + done) + @( \ + echo -e "\n") >>$@ + @( \ + for ident in $(IOCTLS) ; do \ + entity=`echo $$ident | tr _ -` ; \ + id=`grep "$$ident" $(MEDIA_OBJ_DIR)/vidioc-*.xml | sed -r s,"^.*/(.*).xml.*","\1",` ; \ + echo "$$ident\">" \ + >>$@ ; \ + done) + @( \ + echo -e "\n") >>$@ + @( \ + for ident in $(TYPES) ; do \ + entity=`echo $$ident | tr _ -` ; \ + echo "$$ident\">" >>$@ ; \ + done) + @( \ + echo -e "\n") >>$@ + @( \ + for ident in $(ENUMS) ; do \ + entity=`echo $$ident | sed -e "s/v4l2_mpeg_cx2341x_video_\([a-z]*_spatial_filter_type\)/\1/" | tr _ -` ; \ + echo "$$ident\">" >>$@ ; \ + done) + @( \ + echo -e "\n") >>$@ + @( \ + for ident in $(STRUCTS) ; do \ + entity=`echo $$ident | tr _ - | sed s/v4l2-mpeg-vbi-ITV0/v4l2-mpeg-vbi-itv0-1/g` ; \ + echo "$$ident\">" >>$@ ; \ + done) + @( \ + echo -e "\n") >>$@ + @( \ + for ident in $(ERRORS) ; do \ + echo "$$ident" \ + "error code\">" >>$@ ; \ + done) + @( \ + echo -e "\n") >>$@ + @( \ + for file in $(MEDIA_SGMLS) ; do \ + entity=`echo "$$file" | sed $(FILENAME) -e s/"^([^-]*)"/sub\1/` ; \ + if ! echo "$$file" | \ + grep -q -E -e '^(func|vidioc|pixfmt)-' ; then \ + echo "" >>$@ ; \ + fi ; \ + done) + @( \ + echo -e "\n") >>$@ + @( \ + for file in $(MEDIA_SGMLS) ; do \ + if echo "$$file" | \ + grep -q -E -e '(func|vidioc|pixfmt)-' ; then \ + entity=`echo "$$file" |sed $(FILENAME)` ; \ + echo "" >>$@ ; \ + fi ; \ + done) + +# Jade can auto-generate a list-of-tables, which includes all structs, +# but we only want data types, all types, and sorted please. +$(MEDIA_OBJ_DIR)/media-indices.tmpl: $(MEDIA_OBJ_DIR)/v4l2.xml + @$($(quiet)gen_xml) + @( \ + echo "") >$@ + @( \ + echo -e "\nList of Types") >>$@ + @( \ + for ident in $(TYPES) ; do \ + id=`echo $$ident | tr _ -` ; \ + echo "$$ident" >>$@ ; \ + done) + @( \ + for ident in $(ENUMS) ; do \ + id=`echo $$ident | sed -e "s/v4l2_mpeg_cx2341x_video_\([a-z]*_spatial_filter_type\)/\1/" | tr _ -`; \ + echo "enum $$ident" >>$@ ; \ + done) + @( \ + for ident in $(STRUCTS) ; do \ + id=`echo $$ident | tr _ - | sed s/v4l2-mpeg-vbi-ITV0/v4l2-mpeg-vbi-itv0-1/g` ; \ + echo "struct $$ident" >>$@ ; \ + done) + @( \ + echo "") >>$@ + diff --git a/Documentation/DocBook/media/bayer.png.b64 b/Documentation/DocBook/media/bayer.png.b64 new file mode 100644 index 0000000000000000000000000000000000000000..ccdf2bcda95c1ca61cf5aa3d2e4685fc052845ba --- /dev/null +++ b/Documentation/DocBook/media/bayer.png.b64 @@ -0,0 +1,171 @@ +iVBORw0KGgoAAAANSUhEUgAAAlgAAACqCAMAAABGfcHVAAAAAXNSR0IArs4c6QAAAwBQTFRFAAIA +CAICAAQVEQEBAgsAJgECAAogAwsTAQopHQYBNAEAAAxNARQAERIQAhoDABwAABZEHRQKGRYKQw0F +ACMBACUAERwpHR4cVRAFBR5rZhADACR2JiIhBDAGAiWGgQ4AcxQABDYACSeQMSYlJykmESxYlQ4A +PSYZIS05OSsJHS5JOC8kAEMDUC8SADXLNDUzADbEAEsAADX/2RABCFIAAD/qxB0AAD//BFgAK0Vp +WT4r3hwA3RsTRERAAEf/5CIA2iYCCUv+WUgz7iIAOk5g3CgVSU5SiD8uB2sABm8AE1X/U1RQOFyL +4jkfIlz/RV98M1j+G2H/fVk23jtD4T0pXl9ieFtGcV894UIiYWJfAIwA50gOV2p+4kssO2j+dGZx +bG1qVmj/OHH/aHJzfnBX5lQ7B50AZnahdXd0AKUG5V1ARnz/6mErCqgAAKsAent46GBIW4GhAK0A +AK8B42FtALIOin9/ALUAiIOBALkAVIf/6WxWg4eBi4SKJrEAmoVtdY2geoP/rYVXhoyOqYVuJbUh +IrgWX5D/jo6J7nszP7gAsI9S63xnN70zZqO/fZzCOb4+cZr+64dy8otYnJ6b7ImDRcM56IqcWMEo +oJb/N8ZoTMRL7Y9/QchcsaOTo6eohaj/7ZqKXspXj6v9xal+oK+7d7vTUM+Afco5r7CumLTVStKV +bs9ukbb/9qx/9q9l8queoLv/e9R66beG7rDImNRhi9aDwsPAs8bWzcK2cd67jtqP5MWUodyB8b+1 +tMr/z8L/j9+kbOXWnN2ZstD7yc7Rzs7Ly9xb183UwdD/+si/qeOmvuKIx9fj4tPCtuWiqOrL+tS2 +y9v++NPK2dvZt+m0ueq80+Wo3OeSwuy/yezG+d7f/eS/z/DS3uf/6Ono4PC71O39xPb02vPZ/+nR ++Ori6e399+vt+PGz+ur65fL55/Xb4vbh7ffX/PPY8vP9+vLy6Pf36fjr/PfM8vjr//f+/vn48P36 +9vv+/vzf+fv4/fvu//z7+v7//P/7/v/8//QpxAAAAAFiS0dEAIgFHUgAAAAJcEhZcwAAFY8AABWW +AQ2TT8cAAAAHdElNRQfaCRQXGSltwbPRAAAgAElEQVR42u2dDXwU1bXAZwEJtEaNH1nbh68fpoWK +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 diff --git a/Documentation/DocBook/media/crop.gif.b64 b/Documentation/DocBook/media/crop.gif.b64 new file mode 100644 index 0000000000000000000000000000000000000000..11d936ae72e8df6e3179f042b02ca8a032df4b08 --- /dev/null +++ b/Documentation/DocBook/media/crop.gif.b64 @@ -0,0 +1,105 @@ +R0lGODlhuQJGAeMAAAAAAH9/fwCvAP8AANEA0dEAAK8Ar////wCOAAAA0QAA//////////////// +/////ywAAAAAuQJGAQAE/vDISau9OOvNu/9gKI5kaZ5oqq5s675wLM90bd94ru987//AoHBILBqP +yKRyyWw6n9CodEqtWq/YrHbL7Xq/4LB4TC6bz+i0es1uu9/wuHxOr9vv+Lx+z+/7/4CBgoOEhYaH +iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6gQC9vr/A +wcLDxMXGx8jJysvMzc7P0NHS09TV1tfYxbth2d3e3+DRAePk5ebn6Onl4ezt7u3q8fLqANtg7/j5 ++s/z/f4B+wIKHAjsn8F09ex5IciwobuDEM1Bi0ixosWLGDNqrJhQIZdk/htDihxJsiTJiSZTqlzJ +MmNHj1q+tRznsKbNmzhzDoz3EiYWmTN7+vQJgOfQmN5mAjzKtCg9pj+TBoU61ClCqlaAthSKVZdV +dFy7NtHKMqxYW1/PmT2bhOzKtWxlpZUYF4pblXDrvpq7Tq+Tu+UGCB5MuLDhw4gTK17MuLHjx5Aj +S55MubLly5gza95MmVxev0EAkxsg8jNoVXNJ0zy9RPQ41RtNsz6V2vPstlLTwdYo+zap2qt9G3Ed +YLdL4bGAL0VOhLhxjL2Zf1IeXboM56Wtt6KuPXRudM8vVu+eiTt5H9hDjj9vyfyIXrTW80gfO4OC ++/jz69/Pv7///wAG/ijggAQWaOCBCCao4IIMNujggRe4J4IwBxBg4YUYZqjhhhx26OGHIIYo4ogk +loihMBbi1k084VlklgLsWQKjBRJqgIwEBJRyY4UqZsNidhjMGOMkQlLgnjERwkdBjuVpk2QFTB5B +H2/2DUlJkRNYhWQKUTKyJQpdFjHlcUFaSaQxo9nGQph/fCkDm0OMCV2VZh7iZpbnwCYfBnDKcecO +fXq3ojotckRnnXr8SQGWEtQIphuKEhEoEHKKdygHCUiQ6QEJdDrEphWA2oGo3UXaAaMHOHrCpFmY +2gSr6H2XJ5AXoHqBp5xyuimpPfCa6we+6uWqCaiqagKsTAxrBbLz/slqTqEUvWgBqLviSqqvnXpq +rbbZTpDtt9ziSsG3unKraabkltutWMq+UOyswa3A7A/tfjGvDpW6eKm3v+a667i38vvvuQLzW7Cm +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 diff --git a/Documentation/DocBook/dvb/.gitignore b/Documentation/DocBook/media/dvb/.gitignore similarity index 100% rename from Documentation/DocBook/dvb/.gitignore rename to Documentation/DocBook/media/dvb/.gitignore diff --git a/Documentation/DocBook/dvb/audio.xml b/Documentation/DocBook/media/dvb/audio.xml similarity index 79% rename from Documentation/DocBook/dvb/audio.xml rename to Documentation/DocBook/media/dvb/audio.xml index eeb96b8a0864b4329db269902b7be0b32772f382..d64386237207a9f27867fd6e9bee02620ff4c8bb 100644 --- a/Documentation/DocBook/dvb/audio.xml +++ b/Documentation/DocBook/media/dvb/audio.xml @@ -14,17 +14,17 @@ the omission of the audio and video device. audio device. -
+
audio_stream_source_t The audio stream source is set through the AUDIO_SELECT_SOURCE call and can take the following values, depending on whether we are replaying from an internal (demux) or external (user write) source. - typedef enum { - AUDIO_SOURCE_DEMUX, - AUDIO_SOURCE_MEMORY - } audio_stream_source_t; +typedef enum { + AUDIO_SOURCE_DEMUX, + AUDIO_SOURCE_MEMORY +} audio_stream_source_t; AUDIO_SOURCE_DEMUX selects the demultiplexer (fed either by the frontend or the DVR device) as the source of the video stream. If AUDIO_SOURCE_MEMORY @@ -33,61 +33,64 @@ call.
-
+
audio_play_state_t The following values can be returned by the AUDIO_GET_STATUS call representing the state of audio playback. - typedef enum { - AUDIO_STOPPED, - AUDIO_PLAYING, - AUDIO_PAUSED - } audio_play_state_t; +typedef enum { + AUDIO_STOPPED, + AUDIO_PLAYING, + AUDIO_PAUSED +} audio_play_state_t;
-
+
audio_channel_select_t The audio channel selected via AUDIO_CHANNEL_SELECT is determined by the following values. - typedef enum { - AUDIO_STEREO, - AUDIO_MONO_LEFT, - AUDIO_MONO_RIGHT, - } audio_channel_select_t; +typedef enum { + AUDIO_STEREO, + AUDIO_MONO_LEFT, + AUDIO_MONO_RIGHT, + AUDIO_MONO, + AUDIO_STEREO_SWAPPED +} audio_channel_select_t;
-
+
struct audio_status The AUDIO_GET_STATUS call returns the following structure informing about various states of the playback operation. - typedef struct audio_status { - boolean AV_sync_state; - boolean mute_state; - audio_play_state_t play_state; - audio_stream_source_t stream_source; - audio_channel_select_t channel_select; - boolean bypass_mode; - } audio_status_t; +typedef struct audio_status { + boolean AV_sync_state; + boolean mute_state; + audio_play_state_t play_state; + audio_stream_source_t stream_source; + audio_channel_select_t channel_select; + boolean bypass_mode; + audio_mixer_t mixer_state; +} audio_status_t;
-
+
struct audio_mixer The following structure is used by the AUDIO_SET_MIXER call to set the audio volume. - typedef struct audio_mixer { - unsigned int volume_left; - unsigned int volume_right; - } audio_mixer_t; +typedef struct audio_mixer { + unsigned int volume_left; + unsigned int volume_right; +} audio_mixer_t;
@@ -109,17 +112,17 @@ bits set according to the hardwares capabilities.
-
+
struct audio_karaoke The ioctl AUDIO_SET_KARAOKE uses the following format: - typedef - struct audio_karaoke{ - int vocal1; - int vocal2; - int melody; - } audio_karaoke_t; +typedef +struct audio_karaoke { + int vocal1; + int vocal2; + int melody; +} audio_karaoke_t; If Vocal1 or Vocal2 are non-zero, they get mixed into left and right t at 70% each. If both, Vocal1 and Vocal2 are non-zero, Vocal1 gets mixed into the left channel and Vocal2 into the @@ -128,7 +131,7 @@ and right.
-
+
audio attributes The following attributes can be set by a call to AUDIO_SET_ATTRIBUTES: @@ -217,21 +220,13 @@ and right. (blocking mode is the default) -ERRORS - +RETURN VALUE ENODEV Device driver not loaded/available. - - -EINTERNAL - -Internal error. @@ -276,8 +271,7 @@ and right. File descriptor returned by a previous call to open(). -ERRORS - +RETURN VALUE EBADF @@ -332,8 +326,7 @@ and right. Size of buf. -ERRORS - +RETURN VALUE EPERM @@ -358,7 +351,7 @@ and right. -
AUDIO_STOP DESCRIPTION @@ -391,25 +384,9 @@ role="subsection">AUDIO_STOP Equals AUDIO_STOP for this command. -ERRORS - - -EBADF - -fd is not a valid open file descriptor - - -EINTERNAL - -Internal error. - - +&return-value-dvb; -
AUDIO_PLAY DESCRIPTION @@ -443,25 +420,9 @@ role="subsection">AUDIO_PLAY Equals AUDIO_PLAY for this command. -ERRORS - - -EBADF - -fd is not a valid open file descriptor - - -EINTERNAL - -Internal error. - - +&return-value-dvb; -
AUDIO_PAUSE DESCRIPTION @@ -503,25 +464,49 @@ role="subsection">AUDIO_PAUSE Equals AUDIO_PAUSE for this command. -ERRORS +&return-value-dvb; + +
AUDIO_CONTINUE +DESCRIPTION + + +This ioctl restarts the decoding and playing process previously paused +with AUDIO_PAUSE command. + + +It only works if the stream were previously stopped with AUDIO_PAUSE + + +SYNOPSIS + + +int ioctl(int fd, int request = AUDIO_CONTINUE); + + +PARAMETERS -EBADF +int fd -fd is not a valid open file descriptor. +File descriptor returned by a previous call to open(). -EINTERNAL +int request -Internal error. +Equals AUDIO_CONTINUE for this command. +&return-value-dvb; -
AUDIO_SELECT_SOURCE DESCRIPTION @@ -567,32 +552,9 @@ role="subsection">AUDIO_SELECT_SOURCE stream. -ERRORS - - -EBADF - -fd is not a valid open file descriptor. - - -EINTERNAL - -Internal error. - - -EINVAL - -Illegal input parameter. - - +&return-value-dvb; -
AUDIO_SET_MUTE DESCRIPTION @@ -646,32 +608,9 @@ role="subsection">AUDIO_SET_MUTE FALSE Audio Un-mute -ERRORS - - -EBADF - -fd is not a valid open file descriptor. - - -EINTERNAL - -Internal error. - - -EINVAL - -Illegal input parameter. - - +&return-value-dvb; -
AUDIO_SET_AV_SYNC DESCRIPTION @@ -725,32 +664,9 @@ role="subsection">AUDIO_SET_AV_SYNC FALSE AV-sync OFF -ERRORS - - -EBADF - -fd is not a valid open file descriptor. - - -EINTERNAL - -Internal error. - - -EINVAL - -Illegal input parameter. - - +&return-value-dvb; -
AUDIO_SET_BYPASS_MODE DESCRIPTION @@ -808,32 +724,9 @@ role="subsection">AUDIO_SET_BYPASS_MODE FALSE Bypass is enabled -ERRORS - - -EBADF - -fd is not a valid open file descriptor. - - -EINTERNAL - -Internal error. - - -EINVAL - -Illegal input parameter. - - +&return-value-dvb; -
AUDIO_CHANNEL_SELECT DESCRIPTION @@ -877,32 +770,9 @@ role="subsection">AUDIO_CHANNEL_SELECT stereo). -ERRORS - - -EBADF - -fd is not a valid open file descriptor. - - -EINTERNAL - -Internal error. - - -EINVAL - -Illegal input parameter ch. - - +&return-value-dvb; -
AUDIO_GET_STATUS DESCRIPTION @@ -945,32 +815,9 @@ role="subsection">AUDIO_GET_STATUS Returns the current state of Audio Device. -ERRORS - - -EBADF - -fd is not a valid open file descriptor. - - -EINTERNAL - -Internal error. - - -EFAULT - -status points to invalid address. - - +&return-value-dvb; -
AUDIO_GET_CAPABILITIES DESCRIPTION @@ -1013,32 +860,9 @@ role="subsection">AUDIO_GET_CAPABILITIES Returns a bit array of supported sound formats. -ERRORS - - -EBADF - -fd is not a valid open file descriptor. - - -EINTERNAL - -Internal error. - - -EFAULT - -cap points to an invalid address. - - +&return-value-dvb; -
AUDIO_CLEAR_BUFFER DESCRIPTION @@ -1072,25 +896,9 @@ role="subsection">AUDIO_CLEAR_BUFFER Equals AUDIO_CLEAR_BUFFER for this command. -ERRORS - - -EBADF - -fd is not a valid open file descriptor. - - -EINTERNAL - -Internal error. - - +&return-value-dvb; -
AUDIO_SET_ID DESCRIPTION @@ -1136,32 +944,9 @@ role="subsection">AUDIO_SET_ID audio sub-stream id -ERRORS - - -EBADF - -fd is not a valid open file descriptor. - - -EINTERNAL - -Internal error. - - -EINVAL - -Invalid sub-stream id. - - +&return-value-dvb; -
AUDIO_SET_MIXER DESCRIPTION @@ -1202,32 +987,9 @@ role="subsection">AUDIO_SET_MIXER mixer settings. -ERRORS - - -EBADF - -fd is not a valid open file descriptor. - - -EINTERNAL - -Internal error. - - -EFAULT - -mix points to an invalid address. - - +&return-value-dvb; -
AUDIO_SET_STREAMTYPE DESCRIPTION @@ -1270,17 +1032,9 @@ role="subsection">AUDIO_SET_STREAMTYPE stream type -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor - - EINVAL @@ -1288,7 +1042,7 @@ role="subsection">AUDIO_SET_STREAMTYPE -
AUDIO_SET_EXT_ID DESCRIPTION @@ -1330,17 +1084,9 @@ role="subsection">AUDIO_SET_EXT_ID audio sub_stream_id -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor - - EINVAL @@ -1348,7 +1094,7 @@ role="subsection">AUDIO_SET_EXT_ID -
AUDIO_SET_ATTRIBUTES DESCRIPTION @@ -1391,17 +1137,9 @@ role="subsection">AUDIO_SET_ATTRIBUTES audio attributes according to section ?? -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor - - EINVAL @@ -1409,7 +1147,7 @@ role="subsection">AUDIO_SET_ATTRIBUTES -
AUDIO_SET_KARAOKE DESCRIPTION @@ -1422,7 +1160,7 @@ role="subsection">AUDIO_SET_KARAOKE -int ioctl(fd, int request = AUDIO_SET_STREAMTYPE, +int ioctl(fd, int request = AUDIO_SET_KARAOKE, audio_karaoke_t ⋆karaoke); @@ -1440,7 +1178,7 @@ role="subsection">AUDIO_SET_KARAOKE int request -Equals AUDIO_SET_STREAMTYPE for this +Equals AUDIO_SET_KARAOKE for this command. AUDIO_SET_KARAOKE karaoke settings according to section ??. -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor - - EINVAL diff --git a/Documentation/DocBook/dvb/ca.xml b/Documentation/DocBook/media/dvb/ca.xml similarity index 67% rename from Documentation/DocBook/dvb/ca.xml rename to Documentation/DocBook/media/dvb/ca.xml index b1f1d2fad65426eae94dec21d5bba8a91c98bce1..5c4adb44b1c18a4207ac993132e823c83cac6624 100644 --- a/Documentation/DocBook/dvb/ca.xml +++ b/Documentation/DocBook/media/dvb/ca.xml @@ -8,75 +8,85 @@ including linux/dvb/ca.h in your application. CA Data Types -
+
ca_slot_info_t - /⋆ slot interface types and info ⋆/ +typedef struct ca_slot_info { + int num; /⋆ slot number ⋆/ - typedef struct ca_slot_info_s { - int num; /⋆ slot number ⋆/ + int type; /⋆ CA interface this slot supports ⋆/ +#define CA_CI 1 /⋆ CI high level interface ⋆/ +#define CA_CI_LINK 2 /⋆ CI link layer level interface ⋆/ +#define CA_CI_PHYS 4 /⋆ CI physical layer level interface ⋆/ +#define CA_DESCR 8 /⋆ built-in descrambler ⋆/ +#define CA_SC 128 /⋆ simple smart card interface ⋆/ - int type; /⋆ CA interface this slot supports ⋆/ - #define CA_CI 1 /⋆ CI high level interface ⋆/ - #define CA_CI_LINK 2 /⋆ CI link layer level interface ⋆/ - #define CA_CI_PHYS 4 /⋆ CI physical layer level interface ⋆/ - #define CA_SC 128 /⋆ simple smart card interface ⋆/ - - unsigned int flags; - #define CA_CI_MODULE_PRESENT 1 /⋆ module (or card) inserted ⋆/ - #define CA_CI_MODULE_READY 2 - } ca_slot_info_t; + unsigned int flags; +#define CA_CI_MODULE_PRESENT 1 /⋆ module (or card) inserted ⋆/ +#define CA_CI_MODULE_READY 2 +} ca_slot_info_t;
-
+
ca_descr_info_t - - typedef struct ca_descr_info_s { - unsigned int num; /⋆ number of available descramblers (keys) ⋆/ - unsigned int type; /⋆ type of supported scrambling system ⋆/ - #define CA_ECD 1 - #define CA_NDS 2 - #define CA_DSS 4 - } ca_descr_info_t; + +typedef struct ca_descr_info { + unsigned int num; /⋆ number of available descramblers (keys) ⋆/ + unsigned int type; /⋆ type of supported scrambling system ⋆/ +#define CA_ECD 1 +#define CA_NDS 2 +#define CA_DSS 4 +} ca_descr_info_t;
-
-ca_cap_t - - typedef struct ca_cap_s { - unsigned int slot_num; /⋆ total number of CA card and module slots ⋆/ - unsigned int slot_type; /⋆ OR of all supported types ⋆/ - unsigned int descr_num; /⋆ total number of descrambler slots (keys) ⋆/ - unsigned int descr_type;/⋆ OR of all supported types ⋆/ +
+ca_caps_t + +typedef struct ca_caps { + unsigned int slot_num; /⋆ total number of CA card and module slots ⋆/ + unsigned int slot_type; /⋆ OR of all supported types ⋆/ + unsigned int descr_num; /⋆ total number of descrambler slots (keys) ⋆/ + unsigned int descr_type;/⋆ OR of all supported types ⋆/ } ca_cap_t;
-
+
ca_msg_t - - /⋆ a message to/from a CI-CAM ⋆/ - typedef struct ca_msg_s { - unsigned int index; - unsigned int type; - unsigned int length; - unsigned char msg[256]; - } ca_msg_t; + +/⋆ a message to/from a CI-CAM ⋆/ +typedef struct ca_msg { + unsigned int index; + unsigned int type; + unsigned int length; + unsigned char msg[256]; +} ca_msg_t;
-
+
ca_descr_t - - typedef struct ca_descr_s { - unsigned int index; - unsigned int parity; - unsigned char cw[8]; - } ca_descr_t; + +typedef struct ca_descr { + unsigned int index; + unsigned int parity; + unsigned char cw[8]; +} ca_descr_t; -
+
+ +
+ca-pid + +typedef struct ca_pid { + unsigned int pid; + int index; /⋆ -1 == disable⋆/ +} ca_pid_t; + +
+
CA Function Calls @@ -148,8 +158,7 @@ including linux/dvb/ca.h in your application. (blocking mode is the default) -ERRORS - +RETURN VALUE ENODEV @@ -207,8 +216,7 @@ including linux/dvb/ca.h in your application. File descriptor returned by a previous call to open(). -ERRORS - +RETURN VALUE EBADF diff --git a/Documentation/DocBook/dvb/demux.xml b/Documentation/DocBook/media/dvb/demux.xml similarity index 84% rename from Documentation/DocBook/dvb/demux.xml rename to Documentation/DocBook/media/dvb/demux.xml index 1b8c4e9835b9eaac2a52365750b40a6b02d788c8..37c17908aa400acd225881af1acb5383e6221442 100644 --- a/Documentation/DocBook/dvb/demux.xml +++ b/Documentation/DocBook/media/dvb/demux.xml @@ -7,15 +7,19 @@ accessed by including linux/dvb/dmx.h in your app
Demux Data Types -
+
dmx_output_t - - typedef enum - { - DMX_OUT_DECODER, - DMX_OUT_TAP, - DMX_OUT_TS_TAP - } dmx_output_t; + +typedef enum +{ + DMX_OUT_DECODER, /⋆ Streaming directly to decoder. ⋆/ + DMX_OUT_TAP, /⋆ Output going to a memory buffer ⋆/ + /⋆ (to be retrieved via the read command).⋆/ + DMX_OUT_TS_TAP, /⋆ Output multiplexed into a new TS ⋆/ + /⋆ (to be retrieved by reading from the ⋆/ + /⋆ logical DVR device). ⋆/ + DMX_OUT_TSDEMUX_TAP /⋆ Like TS_TAP but retrieved from the DMX device ⋆/ +} dmx_output_t; DMX_OUT_TAP delivers the stream output to the demux device on which the ioctl is called. @@ -26,96 +30,95 @@ specified.
-
+
dmx_input_t - - typedef enum - { - DMX_IN_FRONTEND, - DMX_IN_DVR - } dmx_input_t; + +typedef enum +{ + DMX_IN_FRONTEND, /⋆ Input from a front-end device. ⋆/ + DMX_IN_DVR /⋆ Input from the logical DVR device. ⋆/ +} dmx_input_t;
-
+
dmx_pes_type_t - - typedef enum - { - DMX_PES_AUDIO, - DMX_PES_VIDEO, - DMX_PES_TELETEXT, - DMX_PES_SUBTITLE, - DMX_PES_PCR, - DMX_PES_OTHER - } dmx_pes_type_t; - -
+ +typedef enum +{ + DMX_PES_AUDIO0, + DMX_PES_VIDEO0, + DMX_PES_TELETEXT0, + DMX_PES_SUBTITLE0, + DMX_PES_PCR0, -
-dmx_event_t - - typedef enum - { - DMX_SCRAMBLING_EV, - DMX_FRONTEND_EV - } dmx_event_t; - -
+ DMX_PES_AUDIO1, + DMX_PES_VIDEO1, + DMX_PES_TELETEXT1, + DMX_PES_SUBTITLE1, + DMX_PES_PCR1, -
-dmx_scrambling_status_t - - typedef enum - { - DMX_SCRAMBLING_OFF, - DMX_SCRAMBLING_ON - } dmx_scrambling_status_t; + DMX_PES_AUDIO2, + DMX_PES_VIDEO2, + DMX_PES_TELETEXT2, + DMX_PES_SUBTITLE2, + DMX_PES_PCR2, + + DMX_PES_AUDIO3, + DMX_PES_VIDEO3, + DMX_PES_TELETEXT3, + DMX_PES_SUBTITLE3, + DMX_PES_PCR3, + + DMX_PES_OTHER +} dmx_pes_type_t;
-
+
struct dmx_filter typedef struct dmx_filter - { - uint8_t filter[DMX_FILTER_SIZE]; - uint8_t mask[DMX_FILTER_SIZE]; - } dmx_filter_t; +{ + __u8 filter[DMX_FILTER_SIZE]; + __u8 mask[DMX_FILTER_SIZE]; + __u8 mode[DMX_FILTER_SIZE]; +} dmx_filter_t;
-
+
struct dmx_sct_filter_params - - struct dmx_sct_filter_params - { - uint16_t pid; - dmx_filter_t filter; - uint32_t timeout; - uint32_t flags; - #define DMX_CHECK_CRC 1 - #define DMX_ONESHOT 2 - #define DMX_IMMEDIATE_START 4 - }; + +struct dmx_sct_filter_params +{ + __u16 pid; + dmx_filter_t filter; + __u32 timeout; + __u32 flags; +#define DMX_CHECK_CRC 1 +#define DMX_ONESHOT 2 +#define DMX_IMMEDIATE_START 4 +#define DMX_KERNEL_CLIENT 0x8000 +};
-
+
struct dmx_pes_filter_params - - struct dmx_pes_filter_params - { - uint16_t pid; - dmx_input_t input; - dmx_output_t output; - dmx_pes_type_t pes_type; - uint32_t flags; - }; + +struct dmx_pes_filter_params +{ + __u16 pid; + dmx_input_t input; + dmx_output_t output; + dmx_pes_type_t pes_type; + __u32 flags; +};
-
+
struct dmx_event struct dmx_event @@ -130,19 +133,44 @@ specified.
-
+
struct dmx_stc - - struct dmx_stc { - unsigned int num; /⋆ input : which STC? 0..N ⋆/ - unsigned int base; /⋆ output: divisor for stc to get 90 kHz clock ⋆/ - uint64_t stc; /⋆ output: stc in 'base'⋆90 kHz units ⋆/ - }; + +struct dmx_stc { + unsigned int num; /⋆ input : which STC? 0..N ⋆/ + unsigned int base; /⋆ output: divisor for stc to get 90 kHz clock ⋆/ + __u64 stc; /⋆ output: stc in 'base'⋆90 kHz units ⋆/ +}; -
+
+
+struct dmx_caps + + typedef struct dmx_caps { + __u32 caps; + int num_decoders; +} dmx_caps_t; + +
+ +
+enum dmx_source_t + +typedef enum { + DMX_SOURCE_FRONT0 = 0, + DMX_SOURCE_FRONT1, + DMX_SOURCE_FRONT2, + DMX_SOURCE_FRONT3, + DMX_SOURCE_DVR0 = 16, + DMX_SOURCE_DVR1, + DMX_SOURCE_DVR2, + DMX_SOURCE_DVR3 +} dmx_source_t; +
+
Demux Function Calls @@ -211,8 +239,7 @@ specified. (blocking mode is the default) -ERRORS - +RETURN VALUE ENODEV @@ -271,8 +298,7 @@ specified. File descriptor returned by a previous call to open(). -ERRORS - +RETURN VALUE EBADF @@ -353,8 +379,7 @@ specified. Size of buf. -ERRORS - +RETURN VALUE EWOULDBLOCK @@ -457,8 +482,7 @@ specified. Size of buf. -ERRORS - +RETURN VALUE EWOULDBLOCK @@ -491,7 +515,7 @@ specified.
-
+
DMX_START DESCRIPTION @@ -525,17 +549,9 @@ specified. Equals DMX_START for this command. -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid file descriptor. - - EINVAL @@ -556,7 +572,7 @@ specified.
-
+
DMX_STOP DESCRIPTION @@ -591,19 +607,10 @@ specified. Equals DMX_STOP for this command. -ERRORS - - -EBADF - -fd is not a valid file descriptor. - - +&return-value-dvb;
-
+
DMX_SET_FILTER DESCRIPTION @@ -654,26 +661,10 @@ specified. Pointer to structure containing filter parameters. -ERRORS - - -EBADF - -fd is not a valid file descriptor. - - -EINVAL - -Invalid argument. - - +&return-value-dvb;
-
+
DMX_SET_PES_FILTER DESCRIPTION @@ -727,24 +718,9 @@ specified. Pointer to structure containing filter parameters. -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid file descriptor. - - -EINVAL - -Invalid argument. - - EBUSY @@ -756,7 +732,7 @@ specified.
-
+
DMX_SET_BUFFER_SIZE DESCRIPTION @@ -799,27 +775,10 @@ specified. Size of circular buffer. -ERRORS - - -EBADF - -fd is not a valid file descriptor. - - -ENOMEM - -The driver was not able to allocate a buffer of the - requested size. - - +&return-value-dvb;
-
+
DMX_GET_EVENT DESCRIPTION @@ -872,24 +831,9 @@ specified. Pointer to the location where the event is to be stored. -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid file descriptor. - - -EFAULT - -ev points to an invalid address. - - EWOULDBLOCK @@ -899,7 +843,7 @@ specified.
-
+
DMX_GET_STC DESCRIPTION @@ -946,24 +890,9 @@ specified. Pointer to the location where the stc is to be stored. -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid file descriptor. - - -EFAULT - -stc points to an invalid address. - - EINVAL diff --git a/Documentation/DocBook/dvb/dvbapi.xml b/Documentation/DocBook/media/dvb/dvbapi.xml similarity index 85% rename from Documentation/DocBook/dvb/dvbapi.xml rename to Documentation/DocBook/media/dvb/dvbapi.xml index 9fad86ce7f5e7e6c2e464ed87d42192c47447f49..2ab6ddcfc4e095dada4e2e6eb8084003096c279a 100644 --- a/Documentation/DocBook/dvb/dvbapi.xml +++ b/Documentation/DocBook/media/dvb/dvbapi.xml @@ -114,8 +114,28 @@ Added ISDB-T test originally written by Patrick Boettcher &sub-examples; + + DVB Audio Header File + &sub-audio-h; + + + DVB Conditional Access Header File + &sub-ca-h; + + + DVB Demux Header File + &sub-dmx-h; + DVB Frontend Header File &sub-frontend-h; + + DVB Network Header File + &sub-net-h; + + + DVB Video Header File + &sub-video-h; + diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml new file mode 100644 index 0000000000000000000000000000000000000000..207e1a5bf8f027d8ae073fdabe107a8741598494 --- /dev/null +++ b/Documentation/DocBook/media/dvb/dvbproperty.xml @@ -0,0 +1,859 @@ +
+<constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant> +This section describes the DVB version 5 extention of the DVB-API, also +called "S2API", as this API were added to provide support for DVB-S2. It was +designed to be able to replace the old frontend API. Yet, the DISEQC and +the capability ioctls weren't implemented yet via the new way. +The typical usage for the FE_GET_PROPERTY/FE_SET_PROPERTY +API is to replace the ioctl's were the +struct dvb_frontend_parameters were used. +
+DTV property type + +/* Reserved fields should be set to 0 */ +struct dtv_property { + __u32 cmd; + union { + __u32 data; + struct { + __u8 data[32]; + __u32 len; + __u32 reserved1[3]; + void *reserved2; + } buffer; + } u; + int result; +} __attribute__ ((packed)); + +/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */ +#define DTV_IOCTL_MAX_MSGS 64 + +
+
+DTV properties type + +struct dtv_properties { + __u32 num; + struct dtv_property *props; +}; + +
+ +
+FE_GET_PROPERTY +DESCRIPTION + + +This ioctl call returns one or more frontend properties. This call only + requires read-only access to the device. + + +SYNOPSIS + + +int ioctl(int fd, int request = FE_GET_PROPERTY, + dtv_properties ⋆props); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int num + +Equals FE_GET_PROPERTY for this command. + + +struct dtv_property *props + +Points to the location where the front-end property commands are stored. + + +&return-value-dvb; + + EOPNOTSUPP + Property type not supported. + +
+ +
+FE_SET_PROPERTY +DESCRIPTION + + +This ioctl call sets one or more frontend properties. This call only + requires read-only access to the device. + + +SYNOPSIS + + +int ioctl(int fd, int request = FE_SET_PROPERTY, + dtv_properties ⋆props); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int num + +Equals FE_SET_PROPERTY for this command. + + +struct dtv_property *props + +Points to the location where the front-end property commands are stored. + + +&return-value-dvb; + + EOPNOTSUPP + Property type not supported. + +
+ +
+ Property types + +On FE_GET_PROPERTY/FE_SET_PROPERTY, +the actual action is determined by the dtv_property cmd/data pairs. With one single ioctl, is possible to +get/set up to 64 properties. The actual meaning of each property is described on the next sections. + + +The available frontend property types are shown on the next section. +
+ +
+ Digital TV property parameters +
+ <constant>DTV_UNDEFINED</constant> + Used internally. A GET/SET operation for it won't change or return anything. +
+
+ <constant>DTV_TUNE</constant> + Interpret the cache of data, build either a traditional frontend tunerequest so we can pass validation in the FE_SET_FRONTEND ioctl. +
+
+ <constant>DTV_CLEAR</constant> + Reset a cache of data specific to the frontend here. This does not effect hardware. +
+
+ <constant>DTV_FREQUENCY</constant> + + Central frequency of the channel, in HZ. + + Notes: + 1)For ISDB-T, the channels are usually transmitted with an offset of 143kHz. + E.g. a valid frequncy could be 474143 kHz. The stepping is bound to the bandwidth of + the channel which is 6MHz. + + 2)As in ISDB-Tsb the channel consists of only one or three segments the + frequency step is 429kHz, 3*429 respectively. As for ISDB-T the + central frequency of the channel is expected. +
+
+ <constant>DTV_MODULATION</constant> +Specifies the frontend modulation type for cable and satellite types. The modulation can be one of the types bellow: + + typedef enum fe_modulation { + QPSK, + QAM_16, + QAM_32, + QAM_64, + QAM_128, + QAM_256, + QAM_AUTO, + VSB_8, + VSB_16, + PSK_8, + APSK_16, + APSK_32, + DQPSK, + } fe_modulation_t; + +
+
+ <constant>DTV_BANDWIDTH_HZ</constant> + + Bandwidth for the channel, in HZ. + + Possible values: + 1712000, + 5000000, + 6000000, + 7000000, + 8000000, + 10000000. + + + Notes: + + 1) For ISDB-T it should be always 6000000Hz (6MHz) + 2) For ISDB-Tsb it can vary depending on the number of connected segments + 3) Bandwidth doesn't apply for DVB-C transmissions, as the bandwidth + for DVB-C depends on the symbol rate + 4) Bandwidth in ISDB-T is fixed (6MHz) or can be easily derived from + other parameters (DTV_ISDBT_SB_SEGMENT_IDX, + DTV_ISDBT_SB_SEGMENT_COUNT). + 5) DVB-T supports 6, 7 and 8MHz. + 6) In addition, DVB-T2 supports 1.172, 5 and 10MHz. +
+
+ <constant>DTV_INVERSION</constant> + The Inversion field can take one of these values: + + + typedef enum fe_spectral_inversion { + INVERSION_OFF, + INVERSION_ON, + INVERSION_AUTO + } fe_spectral_inversion_t; + + It indicates if spectral inversion should be presumed or not. In the automatic setting + (INVERSION_AUTO) the hardware will try to figure out the correct setting by + itself. + +
+
+ <constant>DTV_DISEQC_MASTER</constant> + Currently not implemented. +
+
+ <constant>DTV_SYMBOL_RATE</constant> + Digital TV symbol rate, in bauds (symbols/second). Used on cable standards. +
+
+ <constant>DTV_INNER_FEC</constant> + Used cable/satellite transmissions. The acceptable values are: + + +typedef enum fe_code_rate { + FEC_NONE = 0, + FEC_1_2, + FEC_2_3, + FEC_3_4, + FEC_4_5, + FEC_5_6, + FEC_6_7, + FEC_7_8, + FEC_8_9, + FEC_AUTO, + FEC_3_5, + FEC_9_10, +} fe_code_rate_t; + + which correspond to error correction rates of 1/2, 2/3, etc., + no error correction or auto detection. +
+
+ <constant>DTV_VOLTAGE</constant> + The voltage is usually used with non-DiSEqC capable LNBs to switch + the polarzation (horizontal/vertical). When using DiSEqC epuipment this + voltage has to be switched consistently to the DiSEqC commands as + described in the DiSEqC spec. + + typedef enum fe_sec_voltage { + SEC_VOLTAGE_13, + SEC_VOLTAGE_18 + } fe_sec_voltage_t; + +
+
+ <constant>DTV_TONE</constant> + Currently not used. +
+
+ <constant>DTV_PILOT</constant> + Sets DVB-S2 pilot +
+ fe_pilot type + +typedef enum fe_pilot { + PILOT_ON, + PILOT_OFF, + PILOT_AUTO, +} fe_pilot_t; + +
+
+
+ <constant>DTV_ROLLOFF</constant> + Sets DVB-S2 rolloff + +
+ fe_rolloff type + +typedef enum fe_rolloff { + ROLLOFF_35, /* Implied value in DVB-S, default for DVB-S2 */ + ROLLOFF_20, + ROLLOFF_25, + ROLLOFF_AUTO, +} fe_rolloff_t; + +
+
+
+ <constant>DTV_DISEQC_SLAVE_REPLY</constant> + Currently not implemented. +
+
+ <constant>DTV_FE_CAPABILITY_COUNT</constant> + Currently not implemented. +
+
+ <constant>DTV_FE_CAPABILITY</constant> + Currently not implemented. +
+
+ <constant>DTV_DELIVERY_SYSTEM</constant> + Specifies the type of Delivery system +
+ fe_delivery_system type + Possible values: + +typedef enum fe_delivery_system { + SYS_UNDEFINED, + SYS_DVBC_ANNEX_AC, + SYS_DVBC_ANNEX_B, + SYS_DVBT, + SYS_DSS, + SYS_DVBS, + SYS_DVBS2, + SYS_DVBH, + SYS_ISDBT, + SYS_ISDBS, + SYS_ISDBC, + SYS_ATSC, + SYS_ATSCMH, + SYS_DMBTH, + SYS_CMMB, + SYS_DAB, + SYS_DVBT2, +} fe_delivery_system_t; + +
+
+
+ <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> + + If DTV_ISDBT_SOUND_BROADCASTING is '0' this bit-field represents whether + the channel is in partial reception mode or not. + + If '1' DTV_ISDBT_LAYERA_* values are assigned to the center segment and + DTV_ISDBT_LAYERA_SEGMENT_COUNT has to be '1'. + + If in addition DTV_ISDBT_SOUND_BROADCASTING is '1' + DTV_ISDBT_PARTIAL_RECEPTION represents whether this ISDB-Tsb channel + is consisting of one segment and layer or three segments and two layers. + + Possible values: 0, 1, -1 (AUTO) +
+
+ <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> + + This field represents whether the other DTV_ISDBT_*-parameters are + referring to an ISDB-T and an ISDB-Tsb channel. (See also + DTV_ISDBT_PARTIAL_RECEPTION). + + Possible values: 0, 1, -1 (AUTO) +
+
+ <constant>DTV_ISDBT_SB_SUBCHANNEL_ID</constant> + + This field only applies if DTV_ISDBT_SOUND_BROADCASTING is '1'. + + (Note of the author: This might not be the correct description of the + SUBCHANNEL-ID in all details, but it is my understanding of the technical + background needed to program a device) + + An ISDB-Tsb channel (1 or 3 segments) can be broadcasted alone or in a + set of connected ISDB-Tsb channels. In this set of channels every + channel can be received independently. The number of connected + ISDB-Tsb segment can vary, e.g. depending on the frequency spectrum + bandwidth available. + + Example: Assume 8 ISDB-Tsb connected segments are broadcasted. The + broadcaster has several possibilities to put those channels in the + air: Assuming a normal 13-segment ISDB-T spectrum he can align the 8 + segments from position 1-8 to 5-13 or anything in between. + + The underlying layer of segments are subchannels: each segment is + consisting of several subchannels with a predefined IDs. A sub-channel + is used to help the demodulator to synchronize on the channel. + + An ISDB-T channel is always centered over all sub-channels. As for + the example above, in ISDB-Tsb it is no longer as simple as that. + + The DTV_ISDBT_SB_SUBCHANNEL_ID parameter is used to give the + sub-channel ID of the segment to be demodulated. + + Possible values: 0 .. 41, -1 (AUTO) +
+
+ <constant>DTV_ISDBT_SB_SEGMENT_IDX</constant> + This field only applies if DTV_ISDBT_SOUND_BROADCASTING is '1'. + DTV_ISDBT_SB_SEGMENT_IDX gives the index of the segment to be + demodulated for an ISDB-Tsb channel where several of them are + transmitted in the connected manner. + Possible values: 0 .. DTV_ISDBT_SB_SEGMENT_COUNT - 1 + Note: This value cannot be determined by an automatic channel search. +
+
+ <constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant> + This field only applies if DTV_ISDBT_SOUND_BROADCASTING is '1'. + DTV_ISDBT_SB_SEGMENT_COUNT gives the total count of connected ISDB-Tsb + channels. + Possible values: 1 .. 13 + Note: This value cannot be determined by an automatic channel search. +
+
+ <constant>DTV-ISDBT-LAYER*</constant> parameters + ISDB-T channels can be coded hierarchically. As opposed to DVB-T in + ISDB-T hierarchical layers can be decoded simultaneously. For that + reason a ISDB-T demodulator has 3 viterbi and 3 reed-solomon-decoders. + ISDB-T has 3 hierarchical layers which each can use a part of the + available segments. The total number of segments over all layers has + to 13 in ISDB-T. + There are 3 parameter sets, for Layers A, B and C. +
+ <constant>DTV_ISDBT_LAYER_ENABLED</constant> + Hierarchical reception in ISDB-T is achieved by enabling or disabling + layers in the decoding process. Setting all bits of + DTV_ISDBT_LAYER_ENABLED to '1' forces all layers (if applicable) to be + demodulated. This is the default. + If the channel is in the partial reception mode + (DTV_ISDBT_PARTIAL_RECEPTION = 1) the central segment can be decoded + independently of the other 12 segments. In that mode layer A has to + have a SEGMENT_COUNT of 1. + In ISDB-Tsb only layer A is used, it can be 1 or 3 in ISDB-Tsb + according to DTV_ISDBT_PARTIAL_RECEPTION. SEGMENT_COUNT must be filled + accordingly. + Possible values: 0x1, 0x2, 0x4 (|-able) + DTV_ISDBT_LAYER_ENABLED[0:0] - layer A + DTV_ISDBT_LAYER_ENABLED[1:1] - layer B + DTV_ISDBT_LAYER_ENABLED[2:2] - layer C + DTV_ISDBT_LAYER_ENABLED[31:3] unused +
+
+ <constant>DTV_ISDBT_LAYER*_FEC</constant> + Possible values: FEC_AUTO, FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8 +
+
+ <constant>DTV_ISDBT_LAYER*_MODULATION</constant> + Possible values: QAM_AUTO, QPSK, QAM_16, QAM_64, DQPSK + Note: If layer C is DQPSK layer B has to be DQPSK. If layer B is DQPSK + and DTV_ISDBT_PARTIAL_RECEPTION=0 layer has to be DQPSK. +
+
+ <constant>DTV_ISDBT_LAYER*_SEGMENT_COUNT</constant> + Possible values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, -1 (AUTO) + Note: Truth table for DTV_ISDBT_SOUND_BROADCASTING and + DTV_ISDBT_PARTIAL_RECEPTION and LAYER*_SEGMENT_COUNT + + + + + PR + SB + Layer A width + Layer B width + Layer C width + total width + + + 0 + 0 + 1 .. 13 + 1 .. 13 + 1 .. 13 + 13 + + + 1 + 0 + 1 + 1 .. 13 + 1 .. 13 + 13 + + + 0 + 1 + 1 + 0 + 0 + 1 + + + 1 + 1 + 1 + 2 + 0 + 13 + + + + +
+
+ <constant>DTV_ISDBT_LAYER*_TIME_INTERLEAVING</constant> + Possible values: 0, 1, 2, 3, -1 (AUTO) + Note: The real inter-leaver depth-names depend on the mode (fft-size); the values + here are referring to what can be found in the TMCC-structure - + independent of the mode. +
+
+
+ <constant>DTV_API_VERSION</constant> + Returns the major/minor version of the DVB API +
+
+ <constant>DTV_CODE_RATE_HP</constant> + Used on terrestrial transmissions. The acceptable values are: + + +typedef enum fe_code_rate { + FEC_NONE = 0, + FEC_1_2, + FEC_2_3, + FEC_3_4, + FEC_4_5, + FEC_5_6, + FEC_6_7, + FEC_7_8, + FEC_8_9, + FEC_AUTO, + FEC_3_5, + FEC_9_10, +} fe_code_rate_t; + +
+
+ <constant>DTV_CODE_RATE_LP</constant> + Used on terrestrial transmissions. The acceptable values are: + + +typedef enum fe_code_rate { + FEC_NONE = 0, + FEC_1_2, + FEC_2_3, + FEC_3_4, + FEC_4_5, + FEC_5_6, + FEC_6_7, + FEC_7_8, + FEC_8_9, + FEC_AUTO, + FEC_3_5, + FEC_9_10, +} fe_code_rate_t; + +
+
+ <constant>DTV_GUARD_INTERVAL</constant> + + Possible values are: + +typedef enum fe_guard_interval { + GUARD_INTERVAL_1_32, + GUARD_INTERVAL_1_16, + GUARD_INTERVAL_1_8, + GUARD_INTERVAL_1_4, + GUARD_INTERVAL_AUTO, + GUARD_INTERVAL_1_128, + GUARD_INTERVAL_19_128, + GUARD_INTERVAL_19_256, +} fe_guard_interval_t; + + + Notes: + 1) If DTV_GUARD_INTERVAL is set the GUARD_INTERVAL_AUTO the hardware will + try to find the correct guard interval (if capable) and will use TMCC to fill + in the missing parameters. + 2) Intervals 1/128, 19/128 and 19/256 are used only for DVB-T2 at present +
+
+ <constant>DTV_TRANSMISSION_MODE</constant> + + Specifies the number of carriers used by the standard + + Possible values are: + +typedef enum fe_transmit_mode { + TRANSMISSION_MODE_2K, + TRANSMISSION_MODE_8K, + TRANSMISSION_MODE_AUTO, + TRANSMISSION_MODE_4K, + TRANSMISSION_MODE_1K, + TRANSMISSION_MODE_16K, + TRANSMISSION_MODE_32K, +} fe_transmit_mode_t; + + Notes: + 1) ISDB-T supports three carrier/symbol-size: 8K, 4K, 2K. It is called + 'mode' in the standard: Mode 1 is 2K, mode 2 is 4K, mode 3 is 8K + + 2) If DTV_TRANSMISSION_MODE is set the TRANSMISSION_MODE_AUTO the + hardware will try to find the correct FFT-size (if capable) and will + use TMCC to fill in the missing parameters. + 3) DVB-T specifies 2K and 8K as valid sizes. + 4) DVB-T2 specifies 1K, 2K, 4K, 8K, 16K and 32K. +
+
+ <constant>DTV_HIERARCHY</constant> + Frontend hierarchy + +typedef enum fe_hierarchy { + HIERARCHY_NONE, + HIERARCHY_1, + HIERARCHY_2, + HIERARCHY_4, + HIERARCHY_AUTO + } fe_hierarchy_t; + +
+
+ <constant>DTV_ISDBS_TS_ID</constant> + Currently unused. +
+
+ <constant>DTV_DVBT2_PLP_ID</constant> + DVB-T2 supports Physical Layer Pipes (PLP) to allow transmission of + many data types via a single multiplex. The API will soon support this + at which point this section will be expanded. +
+
+
+ Properties used on terrestrial delivery systems +
+ DVB-T delivery system + The following parameters are valid for DVB-T: + + DTV_API_VERSION + DTV_DELIVERY_SYSTEM + DTV_TUNE + DTV_CLEAR + DTV_FREQUENCY + DTV_MODULATION + DTV_BANDWIDTH_HZ + DTV_INVERSION + DTV_CODE_RATE_HP + DTV_CODE_RATE_LP + DTV_GUARD_INTERVAL + DTV_TRANSMISSION_MODE + DTV_HIERARCHY + +
+
+ DVB-T2 delivery system + DVB-T2 support is currently in the early stages + of development, so expect that this section maygrow and become + more detailed with time. + The following parameters are valid for DVB-T2: + + DTV_API_VERSION + DTV_DELIVERY_SYSTEM + DTV_TUNE + DTV_CLEAR + DTV_FREQUENCY + DTV_MODULATION + DTV_BANDWIDTH_HZ + DTV_INVERSION + DTV_CODE_RATE_HP + DTV_CODE_RATE_LP + DTV_GUARD_INTERVAL + DTV_TRANSMISSION_MODE + DTV_HIERARCHY + DTV_DVBT2_PLP_ID + +
+
+ ISDB-T delivery system + This ISDB-T/ISDB-Tsb API extension should reflect all information + needed to tune any ISDB-T/ISDB-Tsb hardware. Of course it is possible + that some very sophisticated devices won't need certain parameters to + tune. + The information given here should help application writers to know how + to handle ISDB-T and ISDB-Tsb hardware using the Linux DVB-API. + The details given here about ISDB-T and ISDB-Tsb are just enough to + basically show the dependencies between the needed parameter values, + but surely some information is left out. For more detailed information + see the following documents: + ARIB STD-B31 - "Transmission System for Digital Terrestrial + Television Broadcasting" and + ARIB TR-B14 - "Operational Guidelines for Digital Terrestrial + Television Broadcasting". + In order to understand the ISDB specific parameters, + one has to have some knowledge the channel structure in + ISDB-T and ISDB-Tsb. I.e. it has to be known to + the reader that an ISDB-T channel consists of 13 segments, + that it can have up to 3 layer sharing those segments, + and things like that. + The following parameters are valid for ISDB-T: + + DTV_API_VERSION + DTV_DELIVERY_SYSTEM + DTV_TUNE + DTV_CLEAR + DTV_FREQUENCY + DTV_MODULATION + DTV_BANDWIDTH_HZ + DTV_INVERSION + DTV_CODE_RATE_HP + DTV_CODE_RATE_LP + DTV_GUARD_INTERVAL + DTV_TRANSMISSION_MODE + DTV_HIERARCHY + DTV_ISDBT_LAYER_ENABLED + DTV_ISDBT_PARTIAL_RECEPTION + DTV_ISDBT_SOUND_BROADCASTING + DTV_ISDBT_SB_SUBCHANNEL_ID + DTV_ISDBT_SB_SEGMENT_IDX + DTV_ISDBT_SB_SEGMENT_COUNT + DTV_ISDBT_LAYERA_FEC + DTV_ISDBT_LAYERA_MODULATION + DTV_ISDBT_LAYERA_SEGMENT_COUNT + DTV_ISDBT_LAYERA_TIME_INTERLEAVING + DTV_ISDBT_LAYERB_FEC + DTV_ISDBT_LAYERB_MODULATION + DTV_ISDBT_LAYERB_SEGMENT_COUNT + DTV_ISDBT_LAYERB_TIME_INTERLEAVING + DTV_ISDBT_LAYERC_FEC + DTV_ISDBT_LAYERC_MODULATION + DTV_ISDBT_LAYERC_SEGMENT_COUNT + DTV_ISDBT_LAYERC_TIME_INTERLEAVING + +
+
+ ATSC delivery system + The following parameters are valid for ATSC: + + DTV_API_VERSION + DTV_DELIVERY_SYSTEM + DTV_TUNE + DTV_CLEAR + DTV_FREQUENCY + DTV_MODULATION + DTV_BANDWIDTH_HZ + +
+
+
+ Properties used on cable delivery systems +
+ DVB-C delivery system + The DVB-C Annex-A/C is the widely used cable standard. Transmission uses QAM modulation. + The following parameters are valid for DVB-C Annex A/C: + + DTV_API_VERSION + DTV_DELIVERY_SYSTEM + DTV_TUNE + DTV_CLEAR + DTV_FREQUENCY + DTV_MODULATION + DTV_INVERSION + DTV_SYMBOL_RATE + DTV_INNER_FEC + +
+
+ DVB-C Annex B delivery system + The DVB-C Annex-B is only used on a few Countries like the United States. + The following parameters are valid for DVB-C Annex B: + + DTV_API_VERSION + DTV_DELIVERY_SYSTEM + DTV_TUNE + DTV_CLEAR + DTV_FREQUENCY + DTV_MODULATION + DTV_INVERSION + +
+
+
+ Properties used on satellital delivery systems +
+ DVB-S delivery system + The following parameters are valid for DVB-S: + + DTV_API_VERSION + DTV_DELIVERY_SYSTEM + DTV_TUNE + DTV_CLEAR + DTV_FREQUENCY + DTV_INVERSION + DTV_SYMBOL_RATE + DTV_INNER_FEC + + Future implementations might add those two missing parameters: + + DTV_DISEQC_MASTER + DTV_DISEQC_SLAVE_REPLY + +
+
+ DVB-S2 delivery system + The following parameters are valid for DVB-S2: + + DTV_API_VERSION + DTV_DELIVERY_SYSTEM + DTV_TUNE + DTV_CLEAR + DTV_FREQUENCY + DTV_INVERSION + DTV_SYMBOL_RATE + DTV_INNER_FEC + DTV_VOLTAGE + DTV_TONE + DTV_PILOT + DTV_ROLLOFF + + Future implementations might add those two missing parameters: + + DTV_DISEQC_MASTER + DTV_DISEQC_SLAVE_REPLY + +
+
+ ISDB-S delivery system + The following parameters are valid for ISDB-S: + + DTV_API_VERSION + DTV_DELIVERY_SYSTEM + DTV_TUNE + DTV_CLEAR + DTV_FREQUENCY + DTV_INVERSION + DTV_SYMBOL_RATE + DTV_INNER_FEC + DTV_VOLTAGE + DTV_ISDBS_TS_ID + +
+
+
diff --git a/Documentation/DocBook/dvb/dvbstb.pdf b/Documentation/DocBook/media/dvb/dvbstb.pdf similarity index 100% rename from Documentation/DocBook/dvb/dvbstb.pdf rename to Documentation/DocBook/media/dvb/dvbstb.pdf diff --git a/Documentation/DocBook/dvb/examples.xml b/Documentation/DocBook/media/dvb/examples.xml similarity index 100% rename from Documentation/DocBook/dvb/examples.xml rename to Documentation/DocBook/media/dvb/examples.xml diff --git a/Documentation/DocBook/dvb/frontend.xml b/Documentation/DocBook/media/dvb/frontend.xml similarity index 75% rename from Documentation/DocBook/dvb/frontend.xml rename to Documentation/DocBook/media/dvb/frontend.xml index 60c6976fb3116c9ac6468381f392eedf0c9ef7a0..61407eaba020342b40d6ba8d5588d4c30e07beb9 100644 --- a/Documentation/DocBook/dvb/frontend.xml +++ b/Documentation/DocBook/media/dvb/frontend.xml @@ -20,22 +20,52 @@ cards, in which case there exists no frontend device.
Frontend Data Types -
-frontend type - -For historical reasons frontend types are named after the type of modulation used in -transmission. - - typedef enum fe_type { - FE_QPSK, /⋆ DVB-S ⋆/ - FE_QAM, /⋆ DVB-C ⋆/ - FE_OFDM /⋆ DVB-T ⋆/ - } fe_type_t; - - +
+Frontend type + +For historical reasons, frontend types are named by the type of modulation used in +transmission. The fontend types are given by fe_type_t type, defined as: + + +Frontend types + + &cs-def; + + + fe_type + Description + DTV_DELIVERY_SYSTEM equivalent type + + + + + FE_QPSK + For DVB-S standard + SYS_DVBS + + + FE_QAM + For DVB-C annex A/C standard + SYS_DVBC_ANNEX_AC + + + FE_OFDM + For DVB-T standard + SYS_DVBT + + + FE_ATSC + For ATSC standard (terrestrial) or for DVB-C Annex B (cable) used in US. + SYS_ATSC (terrestrial) or SYS_DVBC_ANNEX_B (cable) + +
+ +Newer formats like DVB-S2, ISDB-T, ISDB-S and DVB-T2 are not described at the above, as they're +supported via the new FE_GET_PROPERTY/FE_GET_SET_PROPERTY ioctl's, using the DTV_DELIVERY_SYSTEM parameter. +
-
+
frontend capabilities Capabilities describe what a frontend can do. Some capabilities can only be supported for @@ -76,7 +106,7 @@ a specific frontend type.
-
+
frontend information Information about the frontend ca be queried with @@ -99,7 +129,7 @@ a specific frontend type.
-
+
diseqc master command A message sent from the frontend to DiSEqC capable equipment. @@ -110,7 +140,7 @@ a specific frontend type. };
-
+
diseqc slave reply A reply to the frontend from DiSEqC 2.0 capable equipment. @@ -123,7 +153,7 @@ a specific frontend type.
-
+
diseqc slave reply The voltage is usually used with non-DiSEqC capable LNBs to switch the polarzation (horizontal/vertical). When using DiSEqC epuipment this voltage has to be switched @@ -136,7 +166,7 @@ consistently to the DiSEqC commands as described in the DiSEqC spec.
-
+
SEC continuous tone The continuous 22KHz tone is usually used with non-DiSEqC capable LNBs to switch the @@ -151,7 +181,7 @@ spec.
-
+
SEC tone burst The 22KHz tone burst is usually used with non-DiSEqC capable switches to select @@ -168,7 +198,7 @@ spec.
-
+
frontend status Several functions of the frontend device use the fe_status data type defined by @@ -188,31 +218,54 @@ by
-
+
frontend parameters The kind of parameters passed to the frontend device for tuning depend on -the kind of hardware you are using. All kinds of parameters are combined as an -union in the FrontendParameters structure: +the kind of hardware you are using. +The struct dvb_frontend_parameters uses an +union with specific per-system parameters. However, as newer delivery systems +required more data, the structure size weren't enough to fit, and just +extending its size would break the existing applications. So, those parameters +were replaced by the usage of +FE_GET_PROPERTY/FE_SET_PROPERTY ioctl's. The +new API is flexible enough to add new parameters to existing delivery systems, +and to add newer delivery systems. +So, newer applications should use +FE_GET_PROPERTY/FE_SET_PROPERTY instead, in +order to be able to support the newer System Delivery like DVB-S2, DVB-T2, +DVB-C2, ISDB, etc. +All kinds of parameters are combined as an union in the FrontendParameters structure: - struct dvb_frontend_parameters { - uint32_t frequency; /⋆ (absolute) frequency in Hz for QAM/OFDM ⋆/ - /⋆ intermediate frequency in kHz for QPSK ⋆/ - fe_spectral_inversion_t inversion; - union { - struct dvb_qpsk_parameters qpsk; - struct dvb_qam_parameters qam; - struct dvb_ofdm_parameters ofdm; - } u; - }; +struct dvb_frontend_parameters { + uint32_t frequency; /⋆ (absolute) frequency in Hz for QAM/OFDM ⋆/ + /⋆ intermediate frequency in kHz for QPSK ⋆/ + fe_spectral_inversion_t inversion; + union { + struct dvb_qpsk_parameters qpsk; + struct dvb_qam_parameters qam; + struct dvb_ofdm_parameters ofdm; + struct dvb_vsb_parameters vsb; + } u; +}; -For satellite QPSK frontends you have to use the QPSKParameters member defined by +In the case of QPSK frontends the frequency field specifies the intermediate +frequency, i.e. the offset which is effectively added to the local oscillator frequency (LOF) of +the LNB. The intermediate frequency has to be specified in units of kHz. For QAM and +OFDM frontends the frequency specifies the absolute frequency and is given in Hz. + +
+QPSK parameters +For satellite QPSK frontends you have to use the dvb_qpsk_parameters structure: struct dvb_qpsk_parameters { uint32_t symbol_rate; /⋆ symbol rate in Symbols per second ⋆/ fe_code_rate_t fec_inner; /⋆ forward error correction (see above) ⋆/ }; -for cable QAM frontend you use the QAMParameters structure +
+
+QAM parameters +for cable QAM frontend you use the dvb_qam_parameters structure: struct dvb_qam_parameters { uint32_t symbol_rate; /⋆ symbol rate in Symbols per second ⋆/ @@ -220,8 +273,19 @@ union in the FrontendParameters structure: fe_modulation_t modulation; /⋆ modulation type (see above) ⋆/ }; -DVB-T frontends are supported by the OFDMParamters structure - +
+
+VSB parameters +ATSC frontends are supported by the dvb_vsb_parameters structure: + +struct dvb_vsb_parameters { + fe_modulation_t modulation; /⋆ modulation type (see above) ⋆/ +}; + +
+
+OFDM parameters +DVB-T frontends are supported by the dvb_ofdm_parameters structure: struct dvb_ofdm_parameters { fe_bandwidth_t bandwidth; @@ -233,86 +297,124 @@ union in the FrontendParameters structure: fe_hierarchy_t hierarchy_information; }; -In the case of QPSK frontends the Frequency field specifies the intermediate -frequency, i.e. the offset which is effectively added to the local oscillator frequency (LOF) of -the LNB. The intermediate frequency has to be specified in units of kHz. For QAM and -OFDM frontends the Frequency specifies the absolute frequency and is given in -Hz. - +
+
+frontend spectral inversion The Inversion field can take one of these values: - typedef enum fe_spectral_inversion { - INVERSION_OFF, - INVERSION_ON, - INVERSION_AUTO - } fe_spectral_inversion_t; +typedef enum fe_spectral_inversion { + INVERSION_OFF, + INVERSION_ON, + INVERSION_AUTO +} fe_spectral_inversion_t; It indicates if spectral inversion should be presumed or not. In the automatic setting (INVERSION_AUTO) the hardware will try to figure out the correct setting by itself. -The possible values for the FEC_inner field are +
+
+frontend code rate +The possible values for the fec_inner field used on +struct dvb_qpsk_parameters and +struct dvb_qam_parameters are: - typedef enum fe_code_rate { - FEC_NONE = 0, - FEC_1_2, - FEC_2_3, - FEC_3_4, - FEC_4_5, - FEC_5_6, - FEC_6_7, - FEC_7_8, - FEC_8_9, - FEC_AUTO - } fe_code_rate_t; +typedef enum fe_code_rate { + FEC_NONE = 0, + FEC_1_2, + FEC_2_3, + FEC_3_4, + FEC_4_5, + FEC_5_6, + FEC_6_7, + FEC_7_8, + FEC_8_9, + FEC_AUTO, + FEC_3_5, + FEC_9_10, +} fe_code_rate_t; which correspond to error correction rates of 1/2, 2/3, etc., no error correction or auto detection. -For cable and terrestrial frontends (QAM and OFDM) one also has to specify the quadrature -modulation mode which can be one of the following: +
+
+frontend modulation type for QAM, OFDM and VSB +For cable and terrestrial frontends, e. g. for +struct dvb_qpsk_parameters, +struct dvb_qam_parameters and +struct dvb_qam_parameters, +it needs to specify the quadrature modulation mode which can be one of the following: typedef enum fe_modulation { - QPSK, - QAM_16, - QAM_32, - QAM_64, - QAM_128, - QAM_256, - QAM_AUTO + QPSK, + QAM_16, + QAM_32, + QAM_64, + QAM_128, + QAM_256, + QAM_AUTO, + VSB_8, + VSB_16, + PSK_8, + APSK_16, + APSK_32, + DQPSK, } fe_modulation_t; +
Finally, there are several more parameters for OFDM: +
+Number of carriers per channel - typedef enum fe_transmit_mode { - TRANSMISSION_MODE_2K, - TRANSMISSION_MODE_8K, - TRANSMISSION_MODE_AUTO +typedef enum fe_transmit_mode { + TRANSMISSION_MODE_2K, + TRANSMISSION_MODE_8K, + TRANSMISSION_MODE_AUTO, + TRANSMISSION_MODE_4K, + TRANSMISSION_MODE_1K, + TRANSMISSION_MODE_16K, + TRANSMISSION_MODE_32K, } fe_transmit_mode_t; - - typedef enum fe_bandwidth { - BANDWIDTH_8_MHZ, - BANDWIDTH_7_MHZ, - BANDWIDTH_6_MHZ, - BANDWIDTH_AUTO - } fe_bandwidth_t; +
+
+frontend bandwidth + +typedef enum fe_bandwidth { + BANDWIDTH_8_MHZ, + BANDWIDTH_7_MHZ, + BANDWIDTH_6_MHZ, + BANDWIDTH_AUTO, + BANDWIDTH_5_MHZ, + BANDWIDTH_10_MHZ, + BANDWIDTH_1_712_MHZ, +} fe_bandwidth_t; - - typedef enum fe_guard_interval { - GUARD_INTERVAL_1_32, - GUARD_INTERVAL_1_16, - GUARD_INTERVAL_1_8, - GUARD_INTERVAL_1_4, - GUARD_INTERVAL_AUTO - } fe_guard_interval_t; +
+
+frontend guard inverval + +typedef enum fe_guard_interval { + GUARD_INTERVAL_1_32, + GUARD_INTERVAL_1_16, + GUARD_INTERVAL_1_8, + GUARD_INTERVAL_1_4, + GUARD_INTERVAL_AUTO, + GUARD_INTERVAL_1_128, + GUARD_INTERVAL_19_128, + GUARD_INTERVAL_19_256, +} fe_guard_interval_t; - - typedef enum fe_hierarchy { +
+
+frontend hierarchy + +typedef enum fe_hierarchy { HIERARCHY_NONE, HIERARCHY_1, HIERARCHY_2, @@ -320,10 +422,11 @@ modulation mode which can be one of the following: HIERARCHY_AUTO } fe_hierarchy_t; +
-
+
frontend events struct dvb_frontend_event { @@ -412,8 +515,7 @@ modulation mode which can be one of the following: (blocking mode is the default) -ERRORS - +RETURN VALUE ENODEV @@ -473,8 +575,7 @@ modulation mode which can be one of the following: File descriptor returned by a previous call to open(). -ERRORS - +RETURN VALUE EBADF @@ -530,8 +631,7 @@ modulation mode which can be one of the following: to be stored. -ERRORS - +RETURN VALUE EBADF @@ -592,38 +692,8 @@ modulation mode which can be one of the following: The bit error rate is stored into *ber. -ERRORS - - -EBADF - -fd is not a valid open file descriptor. - - -EFAULT - -ber points to invalid address. - - -ENOSIGNAL - -There is no signal, thus no meaningful bit error rate. Also - returned if the front-end is not turned on. - - -ENOSYS - -Function not available for this device. - - + +&return-value-dvb;
@@ -670,38 +740,7 @@ modulation mode which can be one of the following: -ERRORS - - -EBADF - -fd is not a valid open file descriptor. - - -EFAULT - -snr points to invalid address. - - -ENOSIGNAL - -There is no signal, thus no meaningful signal strength - value. Also returned if front-end is not turned on. - - -ENOSYS - -Function not available for this device. - - +&return-value-dvb;
@@ -748,38 +787,8 @@ modulation mode which can be one of the following: The signal strength value is stored into *strength. -ERRORS - - -EBADF - -fd is not a valid open file descriptor. - - -EFAULT - -status points to invalid address. - - -ENOSIGNAL - -There is no signal, thus no meaningful signal strength - value. Also returned if front-end is not turned on. - - -ENOSYS - -Function not available for this device. - - + +&return-value-dvb;
@@ -833,30 +842,8 @@ modulation mode which can be one of the following: so far. -ERRORS - - -EBADF - -fd is not a valid open file descriptor. - - -EFAULT - -ublocks points to invalid address. - - -ENOSYS - -Function not available for this device. - - + +&return-value-dvb;
@@ -909,24 +896,10 @@ modulation mode which can be one of the following: Points to parameters for tuning operation. -ERRORS - + +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor. - - -EFAULT - -p points to invalid address. - - EINVAL @@ -982,25 +955,9 @@ modulation mode which can be one of the following: -ERRORS - - +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor. - - -EFAULT - -p points to invalid address. - - EINVAL @@ -1084,24 +1041,9 @@ modulation mode which can be one of the following: -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor. - - -EFAULT - -ev points to invalid address. - - EWOULDBLOCK @@ -1111,11 +1053,6 @@ modulation mode which can be one of the following: EOVERFLOW - - - Overflow in event queue - one or more events were lost. @@ -1170,23 +1107,7 @@ modulation mode which can be one of the following: to be stored. -ERRORS - - -EBADF - -fd is not a valid open file descriptor. - - -EFAULT - -info points to invalid address. - - +&return-value-dvb;
@@ -1229,30 +1150,7 @@ modulation mode which can be one of the following: -ERRORS - - -EBADF - -fd is not a valid file descriptor. - - -EPERM - -Permission denied (needs read/write access). - - -EINTERNAL - -Internal error in the device driver. - - +&return-value-dvb;
@@ -1302,45 +1200,7 @@ modulation mode which can be one of the following: -ERRORS - - -EBADF - -fd is not a valid file descriptor. - - -EFAULT - -Seq points to an invalid address. - - -EINVAL - -The data structure referred to by seq is invalid in some - way. - - -EPERM - -Permission denied (needs read/write access). - - -EINTERNAL - -Internal error in the device driver. - - +&return-value-dvb;
@@ -1390,45 +1250,7 @@ modulation mode which can be one of the following: Pointer to the command to be received. -ERRORS - - -EBADF - -fd is not a valid file descriptor. - - -EFAULT - -Seq points to an invalid address. - - -EINVAL - -The data structure referred to by seq is invalid in some - way. - - -EPERM - -Permission denied (needs read/write access). - - -EINTERNAL - -Internal error in the device driver. - - +&return-value-dvb;
@@ -1476,45 +1298,7 @@ modulation mode which can be one of the following: -ERRORS - - -EBADF - -fd is not a valid file descriptor. - - -EFAULT - -Seq points to an invalid address. - - -EINVAL - -The data structure referred to by seq is invalid in some - way. - - -EPERM - -Permission denied (needs read/write access). - - -EINTERNAL - -Internal error in the device driver. - - +&return-value-dvb;
@@ -1560,44 +1344,7 @@ modulation mode which can be one of the following: The requested tone generation mode (on/off). -ERRORS - - -ENODEV - -Device driver not loaded/available. - - -EBUSY - -Device or resource busy. - - -EINVAL - -Invalid argument. - - -EPERM - -File not opened with read permissions. - - -EINTERNAL - -Internal error in the device driver. - - +&return-value-dvb;
@@ -1645,44 +1392,7 @@ modulation mode which can be one of the following: -ERRORS - - -ENODEV - -Device driver not loaded/available. - - -EBUSY - -Device or resource busy. - - -EINVAL - -Invalid argument. - - -EPERM - -File not opened with read permissions. - - -EINTERNAL - -Internal error in the device driver. - - +&return-value-dvb;
@@ -1731,44 +1441,7 @@ modulation mode which can be one of the following: -ERRORS - - -ENODEV - -Device driver not loaded/available. - - -EBUSY - -Device or resource busy. - - -EINVAL - -Invalid argument. - - -EPERM - -File not opened with read permissions. - - -EINTERNAL - -Internal error in the device driver. - - +&return-value-dvb;
@@ -1800,11 +1473,7 @@ FE_TUNE_MODE_ONESHOT When set, this flag will disable any zigzagging or other "n -ERRORS - -EINVAL -Invalid argument. - +&return-value-dvb;
@@ -1838,12 +1507,7 @@ sends the specified raw cmd to the dish via DISEqC. -ERRORS - - - There are no errors in use for this call - - +&return-value-dvb;
diff --git a/Documentation/DocBook/dvb/intro.xml b/Documentation/DocBook/media/dvb/intro.xml similarity index 92% rename from Documentation/DocBook/dvb/intro.xml rename to Documentation/DocBook/media/dvb/intro.xml index 0dc83f672ea2eba86d0a8dbfe65d5f6c430b9470..c75dc7cc3e9b6ec167b7fa7091532df7aeac4bd6 100644 --- a/Documentation/DocBook/dvb/intro.xml +++ b/Documentation/DocBook/media/dvb/intro.xml @@ -154,6 +154,10 @@ are called: +/dev/dvb/adapterN/dvrM, + + + /dev/dvb/adapterN/caM, where N enumerates the DVB PCI cards in a system starting @@ -175,10 +179,27 @@ the devices are described in the following chapters. The DVB API include files should be included in application sources with a partial path like: - + + #include <linux/dvb/audio.h> + + + #include <linux/dvb/ca.h> + + + #include <linux/dvb/dmx.h> + #include <linux/dvb/frontend.h> + + #include <linux/dvb/net.h> + + + #include <linux/dvb/osd.h> + + + #include <linux/dvb/video.h> + To enable applications to support different API version, an additional include file
DVB Net Data Types + +
+struct dvb_net_if + +struct dvb_net_if { + __u16 pid; + __u16 if_num; + __u8 feedtype; +#define DVB_NET_FEEDTYPE_MPE 0 /⋆ multi protocol encapsulation ⋆/ +#define DVB_NET_FEEDTYPE_ULE 1 /⋆ ultra lightweight encapsulation ⋆/ +}; + +
+ +
+
+DVB net Function Calls To be written…
diff --git a/Documentation/DocBook/dvb/video.xml b/Documentation/DocBook/media/dvb/video.xml similarity index 81% rename from Documentation/DocBook/dvb/video.xml rename to Documentation/DocBook/media/dvb/video.xml index 7bb287e67c8e9d865c48838fc75837c63c61ae6b..25fb823226b42231f7333212c8256fd8d44a888b 100644 --- a/Documentation/DocBook/dvb/video.xml +++ b/Documentation/DocBook/media/dvb/video.xml @@ -18,15 +18,16 @@ supported on some MPEG decoders made for DVD playback.
Video Data Types -
+
video_format_t The video_format_t data type defined by - typedef enum { - VIDEO_FORMAT_4_3, - VIDEO_FORMAT_16_9 - } video_format_t; +typedef enum { + VIDEO_FORMAT_4_3, /⋆ Select 4:3 format ⋆/ + VIDEO_FORMAT_16_9, /⋆ Select 16:9 format. ⋆/ + VIDEO_FORMAT_221_1 /⋆ 2.21:1 ⋆/ +} video_format_t; is used in the VIDEO_SET_FORMAT function (??) to tell the driver which aspect ratio the output hardware (e.g. TV) has. It is also used in the data structures video_status @@ -36,34 +37,36 @@ stream.
-
-video_display_format_t +
+video_displayformat_t In case the display format of the video stream and of the display hardware differ the application has to specify how to handle the cropping of the picture. This can be done using the VIDEO_SET_DISPLAY_FORMAT call (??) which accepts - typedef enum { - VIDEO_PAN_SCAN, - VIDEO_LETTER_BOX, - VIDEO_CENTER_CUT_OUT - } video_display_format_t; +typedef enum { + VIDEO_PAN_SCAN, /⋆ use pan and scan format ⋆/ + VIDEO_LETTER_BOX, /⋆ use letterbox format ⋆/ + VIDEO_CENTER_CUT_OUT /⋆ use center cut out format ⋆/ +} video_displayformat_t; as argument.
-
+
video stream source The video stream source is set through the VIDEO_SELECT_SOURCE call and can take the following values, depending on whether we are replaying from an internal (demuxer) or external (user write) source. - typedef enum { - VIDEO_SOURCE_DEMUX, - VIDEO_SOURCE_MEMORY - } video_stream_source_t; +typedef enum { + VIDEO_SOURCE_DEMUX, /⋆ Select the demux as the main source ⋆/ + VIDEO_SOURCE_MEMORY /⋆ If this source is selected, the stream + comes from the user through the write + system call ⋆/ +} video_stream_source_t; VIDEO_SOURCE_DEMUX selects the demultiplexer (fed either by the frontend or the DVR device) as the source of the video stream. If VIDEO_SOURCE_MEMORY @@ -72,49 +75,98 @@ call.
-
+
video play state The following values can be returned by the VIDEO_GET_STATUS call representing the state of video playback. - typedef enum { - VIDEO_STOPPED, - VIDEO_PLAYING, - VIDEO_FREEZED - } video_play_state_t; +typedef enum { + VIDEO_STOPPED, /⋆ Video is stopped ⋆/ + VIDEO_PLAYING, /⋆ Video is currently playing ⋆/ + VIDEO_FREEZED /⋆ Video is freezed ⋆/ +} video_play_state_t;
-
+
+The structure must be zeroed before use by the application +This ensures it can be extended safely in the future. +struct video-command + +struct video_command { + __u32 cmd; + __u32 flags; + union { + struct { + __u64 pts; + } stop; + + struct { + /⋆ 0 or 1000 specifies normal speed, + 1 specifies forward single stepping, + -1 specifies backward single stepping, + >>1: playback at speed/1000 of the normal speed, + <-1: reverse playback at (-speed/1000) of the normal speed. ⋆/ + __s32 speed; + __u32 format; + } play; + + struct { + __u32 data[16]; + } raw; + }; +}; + +
+ +
+struct video_size-t + +typedef struct { + int w; + int h; + video_format_t aspect_ratio; +} video_size_t; + +
+ + +
struct video_event The following is the structure of a video event as it is returned by the VIDEO_GET_EVENT call. - struct video_event { - int32_t type; - time_t timestamp; - union { - video_format_t video_format; - } u; - }; +struct video_event { + __s32 type; +#define VIDEO_EVENT_SIZE_CHANGED 1 +#define VIDEO_EVENT_FRAME_RATE_CHANGED 2 +#define VIDEO_EVENT_DECODER_STOPPED 3 +#define VIDEO_EVENT_VSYNC 4 + __kernel_time_t timestamp; + union { + video_size_t size; + unsigned int frame_rate; /⋆ in frames per 1000sec ⋆/ + unsigned char vsync_field; /⋆ unknown/odd/even/progressive ⋆/ + } u; +};
-
+
struct video_status The VIDEO_GET_STATUS call returns the following structure informing about various states of the playback operation. - struct video_status { - boolean video_blank; - video_play_state_t play_state; - video_stream_source_t stream_source; - video_format_t video_format; - video_displayformat_t display_format; - }; +struct video_status { + int video_blank; /⋆ blank video on freeze? ⋆/ + video_play_state_t play_state; /⋆ current state of playback ⋆/ + video_stream_source_t stream_source; /⋆ current source (demux/memory) ⋆/ + video_format_t video_format; /⋆ current aspect ratio of stream ⋆/ + video_displayformat_t display_format;/⋆ selected cropping mode ⋆/ +}; If video_blank is set video will be blanked out if the channel is changed or if playback is stopped. Otherwise, the last picture will be displayed. play_state indicates if the video is @@ -127,17 +179,17 @@ device.
-
+
struct video_still_picture An I-frame displayed via the VIDEO_STILLPICTURE call is passed on within the following structure. - /⋆ pointer to and size of a single iframe in memory ⋆/ - struct video_still_picture { - char ⋆iFrame; - int32_t size; - }; +/⋆ pointer to and size of a single iframe in memory ⋆/ +struct video_still_picture { + char ⋆iFrame; /⋆ pointer to a single iframe in memory ⋆/ + int32_t size; +};
@@ -164,26 +216,26 @@ bits set according to the hardwares capabilities.
-
+
video system A call to VIDEO_SET_SYSTEM sets the desired video system for TV output. The following system types can be set: - typedef enum { - VIDEO_SYSTEM_PAL, - VIDEO_SYSTEM_NTSC, - VIDEO_SYSTEM_PALN, - VIDEO_SYSTEM_PALNc, - VIDEO_SYSTEM_PALM, - VIDEO_SYSTEM_NTSC60, - VIDEO_SYSTEM_PAL60, - VIDEO_SYSTEM_PALM60 - } video_system_t; +typedef enum { + VIDEO_SYSTEM_PAL, + VIDEO_SYSTEM_NTSC, + VIDEO_SYSTEM_PALN, + VIDEO_SYSTEM_PALNc, + VIDEO_SYSTEM_PALM, + VIDEO_SYSTEM_NTSC60, + VIDEO_SYSTEM_PAL60, + VIDEO_SYSTEM_PALM60 +} video_system_t;
-
+
struct video_highlight Calling the ioctl VIDEO_SET_HIGHLIGHTS posts the SPU highlight information. The call expects the following format for that information: @@ -210,7 +262,7 @@ call expects the following format for that information:
-
+
video SPU Calling VIDEO_SET_SPU deactivates or activates SPU decoding, according to the following format: @@ -224,7 +276,7 @@ following format:
-
+
video SPU palette The following structure is used to set the SPU palette by calling VIDEO_SPU_PALETTE: @@ -237,7 +289,7 @@ following format:
-
+
video NAVI pack In order to get the navigational data the following structure has to be passed to the ioctl VIDEO_GET_NAVI: @@ -252,7 +304,7 @@ VIDEO_GET_NAVI:
-
+
video attributes The following attributes can be set by a call to VIDEO_SET_ATTRIBUTES: @@ -347,8 +399,7 @@ VIDEO_GET_NAVI: (blocking mode is the default) -ERRORS - +RETURN VALUE ENODEV @@ -406,8 +457,7 @@ VIDEO_GET_NAVI: File descriptor returned by a previous call to open(). -ERRORS - +RETURN VALUE EBADF @@ -462,8 +512,7 @@ VIDEO_GET_NAVI: Size of buf. -ERRORS - +RETURN VALUE EPERM @@ -488,7 +537,7 @@ VIDEO_GET_NAVI: -
VIDEO_STOP DESCRIPTION @@ -543,26 +592,9 @@ role="subsection">VIDEO_STOP FALSE: Show last decoded frame. -ERRORS - - -EBADF - -fd is not a valid open file descriptor - - -EINTERNAL - -Internal error, possibly in the communication with the - DVB subsystem. - - +&return-value-dvb; -
VIDEO_PLAY DESCRIPTION @@ -596,26 +628,9 @@ role="subsection">VIDEO_PLAY Equals VIDEO_PLAY for this command. -ERRORS - - -EBADF - -fd is not a valid open file descriptor - - -EINTERNAL - -Internal error, possibly in the communication with the - DVB subsystem. - - +&return-value-dvb; -
VIDEO_FREEZE DESCRIPTION @@ -653,26 +668,9 @@ role="subsection">VIDEO_FREEZE Equals VIDEO_FREEZE for this command. -ERRORS - - -EBADF - -fd is not a valid open file descriptor - - -EINTERNAL - -Internal error, possibly in the communication with the - DVB subsystem. - - +&return-value-dvb; -
VIDEO_CONTINUE DESCRIPTION @@ -706,26 +704,9 @@ role="subsection">VIDEO_CONTINUE Equals VIDEO_CONTINUE for this command. -ERRORS - - -EBADF - -fd is not a valid open file descriptor - - -EINTERNAL - -Internal error, possibly in the communication with the - DVB subsystem. - - +&return-value-dvb; -
VIDEO_SELECT_SOURCE DESCRIPTION @@ -769,26 +750,9 @@ role="subsection">VIDEO_SELECT_SOURCE Indicates which source shall be used for the Video stream. -ERRORS - - -EBADF - -fd is not a valid open file descriptor - - -EINTERNAL - -Internal error, possibly in the communication with the - DVB subsystem. - - +&return-value-dvb; -
VIDEO_SET_BLANK DESCRIPTION @@ -835,33 +799,9 @@ role="subsection">VIDEO_SET_BLANK FALSE: Show last decoded frame. -ERRORS - - -EBADF - -fd is not a valid open file descriptor - - -EINTERNAL - -Internal error, possibly in the communication with the - DVB subsystem. - - -EINVAL - -Illegal input parameter - - +&return-value-dvb; -
VIDEO_GET_STATUS DESCRIPTION @@ -903,33 +843,9 @@ role="subsection">VIDEO_GET_STATUS Returns the current status of the Video Device. -ERRORS - - -EBADF - -fd is not a valid open file descriptor - - -EINTERNAL - -Internal error, possibly in the communication with the - DVB subsystem. - - -EFAULT - -status points to invalid address - - +&return-value-dvb; -
VIDEO_GET_EVENT DESCRIPTION @@ -980,24 +896,9 @@ role="subsection">VIDEO_GET_EVENT stored. -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor - - -EFAULT - -ev points to invalid address - - EWOULDBLOCK @@ -1007,18 +908,13 @@ role="subsection">VIDEO_GET_EVENT EOVERFLOW - - - Overflow in event queue - one or more events were lost. -
VIDEO_SET_DISPLAY_FORMAT DESCRIPTION @@ -1063,32 +959,9 @@ role="subsection">VIDEO_SET_DISPLAY_FORMAT Selects the video format to be used. -ERRORS - - -EBADF - -fd is not a valid open file descriptor - - -EINTERNAL - -Internal error. - - -EINVAL - -Illegal parameter format. - - +&return-value-dvb; -
VIDEO_STILLPICTURE DESCRIPTION @@ -1133,32 +1006,9 @@ role="subsection">VIDEO_STILLPICTURE Pointer to a location where an I-frame and size is stored. -ERRORS - - -EBADF - -fd is not a valid open file descriptor - - -EINTERNAL - -Internal error. - - -EFAULT - -sp points to an invalid iframe. - - +&return-value-dvb; -
VIDEO_FAST_FORWARD DESCRIPTION @@ -1200,39 +1050,17 @@ role="subsection">VIDEO_FAST_FORWARD The number of frames to skip. -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor - - -EINTERNAL - -Internal error. - - EPERM Mode VIDEO_SOURCE_MEMORY not selected. - - -EINVAL - -Illegal parameter format. -
VIDEO_SLOWMOTION DESCRIPTION @@ -1274,39 +1102,17 @@ role="subsection">VIDEO_SLOWMOTION The number of times to repeat each frame. -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor - - -EINTERNAL - -Internal error. - - EPERM Mode VIDEO_SOURCE_MEMORY not selected. - - -EINVAL - -Illegal parameter format. -
VIDEO_GET_CAPABILITIES DESCRIPTION @@ -1350,25 +1156,9 @@ role="subsection">VIDEO_GET_CAPABILITIES information. -ERRORS - - -EBADF - -fd is not a valid open file descriptor - - -EFAULT - -cap points to an invalid iframe. - - +&return-value-dvb; -
VIDEO_SET_ID DESCRIPTION @@ -1410,24 +1200,9 @@ role="subsection">VIDEO_SET_ID video sub-stream id -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor. - - -EINTERNAL - -Internal error. - - EINVAL @@ -1435,7 +1210,7 @@ role="subsection">VIDEO_SET_ID -
VIDEO_CLEAR_BUFFER DESCRIPTION @@ -1468,18 +1243,9 @@ role="subsection">VIDEO_CLEAR_BUFFER Equals VIDEO_CLEAR_BUFFER for this command. -ERRORS - - -EBADF - -fd is not a valid open file descriptor - - +&return-value-dvb; -
VIDEO_SET_STREAMTYPE DESCRIPTION @@ -1522,25 +1288,9 @@ role="subsection">VIDEO_SET_STREAMTYPE stream type -ERRORS - - -EBADF - -fd is not a valid open file descriptor - - -EINVAL - -type is not a valid or supported stream type. - - +&return-value-dvb; -
VIDEO_SET_FORMAT DESCRIPTION @@ -1583,17 +1333,9 @@ role="subsection">VIDEO_SET_FORMAT video format of TV as defined in section ??. -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor - - EINVAL @@ -1601,7 +1343,7 @@ role="subsection">VIDEO_SET_FORMAT -
VIDEO_SET_SYSTEM DESCRIPTION @@ -1645,17 +1387,9 @@ role="subsection">VIDEO_SET_SYSTEM video system of TV output. -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor - - EINVAL @@ -1663,7 +1397,7 @@ role="subsection">VIDEO_SET_SYSTEM -
VIDEO_SET_HIGHLIGHT DESCRIPTION @@ -1705,25 +1439,9 @@ role="subsection">VIDEO_SET_HIGHLIGHT SPU Highlight information according to section ??. -ERRORS - - -EBADF - -fd is not a valid open file descriptor. - - -EINVAL - -input is not a valid highlight setting. - - +&return-value-dvb; -
VIDEO_SET_SPU DESCRIPTION @@ -1766,17 +1484,9 @@ role="subsection">VIDEO_SET_SPU to section ??. -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor - - EINVAL @@ -1785,7 +1495,7 @@ role="subsection">VIDEO_SET_SPU -
VIDEO_SET_SPU_PALETTE DESCRIPTION @@ -1827,17 +1537,9 @@ role="subsection">VIDEO_SET_SPU_PALETTE SPU palette according to section ??. -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor - - EINVAL @@ -1845,7 +1547,7 @@ role="subsection">VIDEO_SET_SPU_PALETTE -
VIDEO_GET_NAVI DESCRIPTION @@ -1889,17 +1591,9 @@ role="subsection">VIDEO_GET_NAVI ??. -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor - - EFAULT @@ -1907,7 +1601,7 @@ role="subsection">VIDEO_GET_NAVI -
VIDEO_SET_ATTRIBUTES DESCRIPTION @@ -1951,17 +1645,9 @@ role="subsection">VIDEO_SET_ATTRIBUTES video attributes according to section ??. -ERRORS - +&return-value-dvb; -EBADF - -fd is not a valid open file descriptor - - EINVAL diff --git a/Documentation/DocBook/media/dvbstb.png.b64 b/Documentation/DocBook/media/dvbstb.png.b64 new file mode 100644 index 0000000000000000000000000000000000000000..e8b52fde3d1142e2bd1d00761ca2d2376f7d399e --- /dev/null +++ b/Documentation/DocBook/media/dvbstb.png.b64 @@ -0,0 +1,398 @@ +iVBORw0KGgoAAAANSUhEUgAAAzMAAAGaCAYAAAA7Jx25AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBI +WXMAAA3XAAANiQFmEOuiAAAgAElEQVR42uzdd1RU18I28GdgKFZUBE0saFA0KoqFFkEhKhbAQmxJ +bIkNNEpMEUwsMZarJMZrw4KxRExQczUqil0jRBA1GAjGQqLYC4TemdnfH76cj3HodYDntxaLmTll +zuw57Zmz9z4yIYQAkYZzcnJCSkoKGjZsyMIgIiIiquPS09PRoEEDyBhmqCaQyWRo06YN3nvvPRYG +ERERUR137Ngx/Pnnn5CzKKgmMDAwwKpVqxhmiIiIiAj29vZ4//33ocWiICIiIiKimohhhoiIiIiI +GGaIiIiIiIgYZoiIiIiIiBhmiIiIiIiIYYaIiIiIiIhhhoiIiIiIiGGGiIiIiIgYZoiIiIiIiBhm +iIiIiIiIGGaIiIiIiIgYZoiIiIiIiGGGiIiIiIiIYYaIiIiIiIhhhoiIiIiIGGaIiIiIiIgYZoiI +iIiIiBhmiIiIiIiIYYaIiIiIiIhhhoiIiIiIqFLIWQRElSMsLAy2trZo1KgR5HJualTxEhIS8P33 +3+PDDz+sM5+5bdu2ePDgAZo2bcoVgCplm3J0dMS5c+fqzGf++uuvsWTJEm5TVClSU1ORk5ODBw8e +oHXr1gwzRDVJbm4uAGDRokUwMDBggVCFmzlzJrKysurUZ3727BksLCzg4eHBFYAq3IIFC5CQkFCn +PnNGRgYAYNWqVVwBqMJFRUVh48aNUCqVlfYeDDNElWzGjBkMM1QpNm7cWOc+c8uWLTFjxgzMmDGD +KwBVuLt37yIkJKTOfW5nZ2duU1SpYaYysc0MERERERHVSAwzRERERETEMENERERERMQwQ0RERERE +xDBDREREREQMM0RERERERAwzREREREREDDNERERERMQwQ0RERERExDBDRERERETEMENERERERMQw +Q0REREREDDNEREREREQMM0RERERERAwzRERERETEMENERERERMQwQ0RERERExDBDREREREQMM0RE +RERERAwzREREREREDDNEREREREQMM0RERERExDBDRERERETEMENERERERMQwQ0REREREDDNERERE +REQMM0RERERERAwzRERERETEMENERERERMQwQ0REREREVGnkLAKimunBgwdISkoq8/SGhoZ47bXX +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 +AADISP8FpxZnWS0U37cAAAAASUVORK5CYII= diff --git a/Documentation/DocBook/media/fieldseq_bt.gif.b64 b/Documentation/DocBook/media/fieldseq_bt.gif.b64 new file mode 100644 index 0000000000000000000000000000000000000000..b5b557b88158e2b35778964edb9a3ae7f330487c --- /dev/null +++ b/Documentation/DocBook/media/fieldseq_bt.gif.b64 @@ -0,0 +1,447 @@ +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 +l3O5NwEBADs= diff --git a/Documentation/DocBook/media/fieldseq_tb.gif.b64 b/Documentation/DocBook/media/fieldseq_tb.gif.b64 new file mode 100644 index 0000000000000000000000000000000000000000..7b4c1766b40774e4ed2b7b0b2ce47f4e57e60326 --- /dev/null +++ b/Documentation/DocBook/media/fieldseq_tb.gif.b64 @@ -0,0 +1,445 @@ +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 +kh6JXympkivJkm4TEAA7 diff --git a/Documentation/DocBook/media/nv12mt.gif.b64 b/Documentation/DocBook/media/nv12mt.gif.b64 new file mode 100644 index 0000000000000000000000000000000000000000..083a7c85d1078aeb4472571430608d19cdbc947b --- /dev/null +++ b/Documentation/DocBook/media/nv12mt.gif.b64 @@ -0,0 +1,37 @@ +R0lGODlhFgFnAMZnAAAAAAYCAgAASAwFBQAAdEgAACQODkgASCoQEEgAdHQAADATEjUVFHQASDsX +F3QAdE0eHVMhIABISABInEhIAIM0Mok2NI84Nk9PT5o9O5xIAHRInFlZWaxEQbhJRgB0v75LSLhQ +TbRTUcBRTrBXVatcWsJWVKdfXW9vb6VhX0h0v8RcWZhpaJJubpBwb8ZiX8ZiYI5zc4t1dYd4eMhn +Zb90AIN8fH9/f8pracpta8ttasxzcM51dM52dM53dc94dkic39F+fNOEgpmZmdWJh9ePjdiTkt+c +SNuamd2gnt6lo3S//5y/nOCqqeKwr+S1tOa7uv+/dOjBwOrGxuzKye3KyuzMy5zf/7/fnO/S0fHX +1//fnPPd3fTe3vXj4vfo6Pnu7r////v09N////35+f//v///3/////////////////////////// +/////////////////////////////////////////////////////////////////////////yH+ +FE5WMTJNVCBtZW1vcnkgbGF5b3V0ACwAAAAAFgFnAAAH/oBngoOEhYaHiImKi4yNjo+QkZKTlJWW +l5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGmkM3ysvMzc7P +0NHS0CjT1tfY19XZ3N3Y297h4sxDlQDj6OLn6ezZ6+3w0u/x9M0A5r/3vvq9/Lz+kQDqEpiLIC6D +txAyUliLIS2HsyDKkniIIiyLrzC60tiKoyCPq0CqEpmKJCqQJk+lNLWyVEtSKPPJ3Ddz0stRN0Xl +DLUTVEyaQPvVlNTzU1FPRzsl5fRTaNB/QwNGHTi1IL6nu5Zu0qqpKVSsVME+4pqJLCazl9Ba8oqp +jAIA/gTCIOXkVsAVo52OAABgV6kmMxr2Cgbil9LLGh/OIJ6r6QgBLAfuMm48YYzPT1siF7a5qUyD +u1HibtaUWfLoS55NT+a0+DSklqXPxK5EJkuhm7NdV8pMYW9i3YJsT8q99Wqm2MQn/cihZRBuzasv +RenrdgnwM8uFQzpSOfrrTcihW5KyogiYM89VF9cUWq7i3+sRTVlB5Lyj6ngNd/58pn0mMUmY4ER6 ++R2nGWCEMbUIGQE2QUYj3Fnm3VibIPgeJ178kEFz4Imn4F8aEJbcWY18EcQLViziVoITOvLSFgXA +5R4iVvxg44045oijByAU0QMIQAYppJAwPHhIFILx/qUeieDFCIB1igjBg45U4nhBlVSaAEIQYiTi +2IzXLbTKF1mUaeaZaJr5RAc5aKeIFStw0RErVehARZp4mrlAnmlCscILU8yp3y5iILECBI7AKaeg +q3DxQ5cuMgLgCg5uZBwuTpiAhBgQKZqRK45CKqYiftZ30aW1WEFDEF58xIinn4L6aCMIabHDDhye +OqgtYgSRonOLwBqrrKImglAQUjyEalg0xjlRLKEuotayFIoliLC6whKtsVVFai222Wo7KyLT7kpU +VeCGK26xhJTLmblZGZKuuutW1C2tUc1Lb7233TuqU9c6m9At2wJrLb68JEEGP/rG4u4iBaPnr7S8 +/ohhgsRnNOxwLgU/LJVh9YR8Qwsl3HCOCyHIIDI986yMjgwkzKBMyy63g1LN8JzAgskoq4wzOzT/ +3E0MIIiQggM2CG0ztbW88MUZDAgc7y5aFlHBCDsk4ebA8NryxQsZd7DoV7oIQcQKBpyhRRM/jOCE +VV3X8kQRcKYtCBnsNsQLFHSLPQjecL+bi9lxApCFEjuM0ASzuXwNtdSMf5yLlkQEAcIOSmzN9S5O +A6Dxs3HPogUIOSBhRQATy1LEE/d8vq+3t5BhhH0YA6zLFELo47qlocNChhC/unowLRYzDLnevbvy +e/DC265LEqgPsntITCsPvCEef4fV9CVVz8ry/vYOjzwh3KvkvSrgh+985AGPDbrgvl9PbuoRNev+ +6wjHzzz29L8v7/G8g18r0sct8SkrEeXTyfkigaS9sIgRBCwge/bSlzBNAjAV/BACAXgIGAmmOxo8 +lybK8AC5TGdJh4igBAuhOUaUYQOWqQEIMVGb2jVGAh6iRA0N9iYOFmJE8RFhJ/CzIPn9qxDZoYR/ +NLEcBNClAUzIISWWw6FO+XAQQOzKAocjxUKoUBEImY+pIAEY+GhCCh0wT2OAkEVJkMc8EtGYB/cC +pRBKjjVmTKER85fCBhlpEQ2c4SYGEKC3XWILCQhDGyUBIBNE4BG7O0IGtZg8SkRIEV+k2CJM/oSi +R0gShWs5Q4aYY4kaiKiLlvDCBUjZCNcRMYh3zMSXFuEDHGAJS1e65Y20xKVGvPJNurTSjUbQox8N +6ZhAosEf3ZIkADxQXsHU0QWI6SNkIrNIKlJAHSkpwEvIUEKK6AKfxrmncZbJT4BSxBZUIIgTlsic +ZyrnE1bQJkws8gxkgieaIEDPFkaiBlCapR21dxwn7UWQTErEpCqlCMBQEJRrKdQKnkAaVFKiUB2g +aEEPCk5YEpRshygV7VwRAU3lbRaZQsIA+qc+kBLCVriKhaos0CpcqIpVNpxaNwNXCGTJoldWyJ5C +fcVDl35Up0blKVJjyT6lNvUgW/TfUp+6jzkhJhWqBqxfJQ+4Pqd6FXZXrepUv8rHsWK1q2e1qlnF +SlVbsKWt4wurW6O6saxKFa5gZCn+5mrXiijNZn8FWmDTEbTBuqMSHDDsODCgWHEwtrHeeCxkucGB +Y1j2spjNrGY3y9nOevazoA2taEdL2tKa9rSoTa1qV8va1rr2tbCNrWxnS9va2va2uM3tLQIBADs= diff --git a/Documentation/DocBook/media/nv12mt_example.gif.b64 b/Documentation/DocBook/media/nv12mt_example.gif.b64 new file mode 100644 index 0000000000000000000000000000000000000000..a512078c7f24fc0f216db7b89a4b1c322bedfaf7 --- /dev/null +++ b/Documentation/DocBook/media/nv12mt_example.gif.b64 @@ -0,0 +1,121 @@ +R0lGODlhoAHkAOe1AAAAAAAASAAAdEgAAEgASEgAdBgYGHQAABoaGnQASHQAdC0eHigoKEIlJEYm +JS4uLlssKzY2NgBISFIyMQBInEBAQEhBQUhIAFBBQVhCQkhISF5DQ2NDQmdDQ3NEQ05OToNGRHhJ +SJxIAItHRY9HRXRInJdIRlpaWppLSaJJRqpJR7BIRa5KR2NfX7JKR2BgYGxdXWleXmZfX31ZWXJc +XHpaWQB0v29dXLZKSHhbWolXVpVUU5JVU55SUJhUUqdQTrpLSK9OTKRRT6FSULRNS7hMSrVNSr5L +SL9MSr1OS7xQTsBRTrtTUL5WU7lYVsJWVEh0v7deW4pqab5dW8RcWbdgXrZjYcZgXnd3d8ZiX8Zi +YL9lY7RoZshnZb90ALJubLFwb8prabBzccpta79wbsttaqx6ecxzcKt8e4aGhr93dc10cs51dM52 +dImJib97ec53dc94dqiEhKeHhkic39F+fKeKiaWPj9OEgqSSkb6PjtWJh5qamqGamqCcnNePjZ+f +n9iTkr6amtiUktmVk9+cSL6enduamb+jo92gnr+pqd6lo7Ozs7+wsHS//7W1tZy/nOCqqbm5ub+4 +uOKwr+S1tL+/v9+/dOa7uv+/dOjBwOrGxuzKye3KyuzMy5zf/7/fnO/S0d/fnPHX1+Dg4P/fnPPd +3fTe3vXj4vfo6L//v+/v7/nu7r///9//v/v09N//39////35+f//v///3/////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////yH+EUNyZWF0ZWQgd2l0aCBH +SU1QACwAAAAAoAHkAAAI/gBrCRxIsKDBgwgTKlzIsKHDhxAjSpxIsaLFixgzatzIsaPHjyBDihxJ +sqTJkyhTqlzJsqXLlzBjypxJs6bNmzhz6tzJs6fPn0CDCh1KtKjRo0iTKl3KtKnTp1CjSp1KtapV +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 +XnvvxTdfffflt19//+03IAA7 diff --git a/Documentation/DocBook/media/pipeline.png.b64 b/Documentation/DocBook/media/pipeline.png.b64 new file mode 100644 index 0000000000000000000000000000000000000000..97d9ac0074733131521e119599581392a69574e8 --- /dev/null +++ b/Documentation/DocBook/media/pipeline.png.b64 @@ -0,0 +1,213 @@ +iVBORw0KGgoAAAANSUhEUgAAAlgAAAEcCAMAAAAsmToJAAAAAXNSR0IArs4c6QAAAwBQTFRFAAEA +EAEBAwUBCgMBCAUKAgkMHQIDCwYXFQYDBgkVDwgFCAsHChASJwkDFA4NEg4TDhANHgwHDg8aExAG +DBEjBBUZERMQCBNRDxU0ExcZFRgVFRcgCRkzHBcUDRdCNRELIxYTAx4mLBUMEBwcEhsiDxwhExsu +Dh8XJRkQByAtDCMUHx4bACk0DSsiGScsFCRcJSUiGSZCDiwqGCg1LyQbIycpVhsPDy0wNyQVECxA +PSIfCS84ADJCEStWRiIULSwpADdHCDkgEy1/BjorEjhADDhXCzZvITNPUysQDzs8MjIvCj04BT1O +PDEoQjEhMDU3LzY9KTdFTTMYNzk2GD6PAEpfEUVjBExFCEpPB1ArK0FjKEVZYTscdDYXG0d5SkA5 +FEiJQUNAOURPAFhCA1RpP0ZJVEMvYUAyBFtRWkYnDlR+QEleAF1jkTojHlV1AGB4PlN5YU87cUws +SVRXAGaBWVJKUlRRRVZlAG1PWFNSBGt5AmqVAG+NAHNpK17BWl9ifFs9KWmnSGZ0YGFfp1IuCnWj +AHuKbWBXoVNAdGBPDniWAHujTWmLk14rAH+ch19XX2aRX2t8AIeLiWgvAIeeAIaqa21rOnehdW1m +AImspWJYj2tLW3C0AIyvWXaNAo6xb3Z5dXZzent4WIKiQojAen+CkX1pcoSWcYDOoH9fp4E+Y4ur +hoWCXIvGb4mut3xpqYNYnYdUO5rDyXxdjY6LYJqk0IRGb5azXZnMjJGUgJWqpJB8l5aUyJN4kKK1 +rZ6IYqzge6Xho6GdnaWpgqy6yZ9zvaR0hqzMk6rN5Jxxw6mF26lbq7C2pLTGwrCbs7Owvb+8zcGc +8rp42L2xsMbY3L+jtMfsz8W2nM/yx8jH0MfA7MWU78h/3crIyNTo4NLD6dK1z9bc1dbT3NXOv9vr +/OKSwur8++Gw4uTh0ef78uPU+OPL3Ojz++bGyfH36evo/+3b6vT88vPw/feu1/v+//bb//nK/PnW +5f/+//ro+fv49/7///37//71//3//v/8sZeTnQAAAAFiS0dEAIgFHUgAAAAJcEhZcwAAFY4AABWO +AUTUBDsAAAAHdElNRQfaCRQPAiJBEFMLAAAgAElEQVR42u2dD3wU5bX300nWws50shA4lyTGikRE +Qy0aUChKvJZqTQGBFNurVo0FWq2VqhAq0hc0t1rAxtLLpu61cUl6gWtNe3vb7Z9IKm+Xqn2tkFih +GmwFA9Xwpw1s/UOyCc97zvPM7L/sbjabXTLZPL/PhzA7O7M7s893zjnPmec5k8WkpNKgLPkTSEmw +pCRYVlSjp5n/3+3xGGsONHt2vx1t04PNTbtP8aUujxAuHvN6XjHe721pbmqLsp/H021+crP5wce8 +Ta8Evi+wKMHKHKkwjf/vA+D/77SrAKDeeTRiO3/vcnzDoTzXgy/+CEKMbVdw5dh9tMGubAfuuMjf +E7HnfgAf/X9yJn6Aupqv206fNfYdXHr/Aloc944EK7PBWg9QurVxlQ3s70Vs+FmAdQ0LAP6By1cA +KCT2AsBqXKme7mEfajBr25MaTIjkSjPA0mHsVnz/G8jgzyBna4MGH/UzdgHYt9ZrMNovwcpksN4E +eJpeHbLB5PDtelT4L/wP4Fr+95NirQa34d85cB1jX3eAsGVhiPRuR644WPjOafxgHXw9uD8axL/k +3+gj3P4vLgJ0SrAyGaxzoFCsfpObJh8aJVMtzUSMA3JZTw/Ab8RKYcD+Rvu2ehsJJIBu9llFwdW3 +0l8N1B0CrDlgpz1K4OfIkRqgT4cOjNkkWBkLFiM4ejT4nXjVrcH/wb9G4BUUwOcZ+xCgtkh74Ci9 +9Iu1Jig/BjhDhmzCGUTzccaKNx9lAqwSUAVY17Kvw7U7S2wLn6fXRXCzn90P2dIVZhxYIlxSiCE0 +W+8F1l+GYDU0hG99P9/gVxiEKxiGvYPMoCMjT2a8fxyRQkQw9HpJg3EBGAmsr4PDz8Eaxz4F+UBf ++DjtMZ0WJ/9ZBu8ZDlZwfX7fjTG0x9ibPTF93D52UEdELgD9LXYw19zteA7onMwLAHuI74SB9QGG +b372DKAvLQF4xN/7FPlR/17gjD3H/BKszHWFYRbr6siEA7sL4Jbga4zG2Yd2sCuqaoC1H63YS3wJ +nSW3RyFgsQ0coQLsNn4KdD/3gtcauG0HOCItVgYH78EYq4fHWOFaDLA6tMNHe3St0m0L3+Ixln+/ +BqP3ib0xGue2LRQstmu+vXjz13mMZYRbubhoFw7yXyRYmdwrHMN7hR/fgVGSdrovVzvEUpuXYPhn +wG9+wJcOaTDZ3GcOpU/fiACLmb3CP5o0ncemCcamQY4EK+PzWD3zYayNYvcwYUj0UiCldTf+9yXQ +2RNlKl+6Aw2YLRCtU/D+uBZgxQDr9iIkrauIeo067OOu8Cfs38Fxgi9+XoKVyWCx+wBKG5t1tDfU +9ME81hlybtki3U59w9XNuOVL/r+IJbu/58yXwOgGdPd0aXAuwXU384eAdT7YtzXqPPO+HuybPRdA +9hnW5YDR2zz41ntnJFiZDBbbbnfQvUI7OBaF5bF+ZdwehALCj+4n2n9qLDkK/8zxMdSNjlA/3UP4 +vRFqsf4+xhG4V8h3G0sB+/4ptJjzB5luyDDV1otUVXd9vbGmpXFr09td96mXha5kT9Yb4psfbKxv +EgMdDjZuE2MTzPfru/9eX/8HsabWeMcY3eBtaHrL+LiDjVt3B75v224/k2CNFL3+D/kbSLCkJFhS +EiwpKQmWlARLSoIlJSXBkpJgSUmwpKQkWFISLCkJlpSUBEtKgiUlwZKSkmBJSbCkJFhSUhIsKQmW +leRP28f50/H5EizLSlHEDC9jCuGxJ6crtoU7TkVjxJxkuGu+XVvNp9t0bS9SFu4Ra1+/PTt/c+R+ +uFLbfMJYtNvMbRk7nq34JFiZrPB5hYdsoKqqA9Sjfbm61ZhkOAdwG1D3IVd2WhJFGp4CB+6Xw8Iq +kD6j0QbZR3D3F/he8CPjHT1s3r0EK8PB6rHBLARmby7kRm538i4QYP2Jag4dmwkOKkU69gjbqcEb +rOddgD1sL8DDofu8D/C4/9gCyPHTrNVZp3oXixpZjCCVYI0gsHy8Tihjf1Rt+Le7pSWw2U4bjBZg +faUEkRJ1QETZte8ShefDT3CxtukV1tXSQm6yBXf+d7Nc0T9o2/d4SUjCyf8iTJZgjTCwng2+FVKG +janqMn9o3UgDLOKmy1g83NrKQ6zzwc493+/YFFFKpoAqIuk03/5dmoCP1g/00xKsjAerpIWLYzMK +oDTw9ACfqgY2w7A8rCDpHEETzZb+kPgCeIpqAz7HOD0PI2yXMfYpUcS2gGosLwf7bq8G1zNuwn7D +JFgZD1ZAFBWdTxVBcjZHezJFKFhPAfyQwLqDu0LOGCysmi8qHS0G+Dg6wR4qJHKCVy4ajWtn0lec +SzvfDzczCVbmg1VQxWVgs2E6oaY/HgcsP3FVKvB6pGUDCLCu53aMB+eE0E9E3y9ntxet4Gh6a/QD +q3Qi62UYyyRYIyzdwPt/O2/Xg+X4+oJF1bNhEV/k1YgWCVdIXvGfIupCS6Xz9/8+xQGQOwddoXh8 +ABqv/8JNf9/a2goQ0jWQYGU2WH7W0cbJ6dL6lLYNsVi3AnzNWHfwyXV7WDCOZyI4p7ptRvW/XdVb +T8/B4P1TZtnRccFCWqoEa6RYrCvUfHPt5JhgfTeQ5uxobz1DVd7HElH0rIq/cb5wAx3yCLTDbf4z +It1gxPElMAE7mCQqFS/BGilgIRiXdeDyTkoWsO7W1ihgvYkheCuJPz7nBDumUTbrV5D3NvOdT2VI +j2O8hRudxz/8YT97EXL9fnSFz/nZq4FnpbA+z7yQYGVyjLXcAXb+MIFFEXmsIFi5gU6kv0tFs6OK +eGsBf1iF9g9yhLnMz0vh+u/npd3VN/j7/EEBpWcCYMngPaOlqCWhSatd84tUteDGHZF5LAKLv+xR +TeGLQ/N1dcZm8faGEjV/4VF0hCoHaaaqnOIrtYXivuP2MlBnBOvEq6oESyq+QobC9ER7vydyq5Eq +CZaUBEtKgiUlwZJKnyqmlXRLsKRSrhJlBI5KlmClX+USLKl0qFKCJZUO1UqwpNKhZkVtl2BJpVzt +qtIswZJKvRSlUoIllQ6wFAmWVOqlKkq3BEsq5apWyzokWFIpV4eiVEiwpNISZHVLsKRSrlpFaZBg +SaVeoCidEiyplKthZGYcJFhpV4FSPgIHZUmw0q8KtFkdEiypVKsbwVIafBIsqVSrhNCq7ZBgSaU8 +gie2ytq6JVhSqVWVSlZLbeiUYEmlVp4ChexWebsESyq16qzgZmtahwRLKg1mSylvlGBJpVotQLGW +T4IllXKrpYyAjKkEaygEmU+WBGtINE3J9AmHEqwhIwskWFKpV4mi1EuwpFIvJbMHAEqwhkrNme0M ++4Dl6+w4++rs7EnT+Q3R6SRysxm7hu3D5HQGC1Z3x7Kc8RNnX2XIds1VadXU8ebS7Ik2W+pHlfja +Z+RMnBg4CVt6z+YqW+CHmzrRNr6x39PpUJQBPQjF10anY37HNek+nYkXm42Dp6N5O5MHy9eQs8Lt +CqpufOirNGjtNaGv3POyWlOJVWeVbW3YCUysS+/pTHWGnc5VOYf7OcKCgSSzOm8cXxN6Au7x6T0b +15IVoSy4LtYOJwlWs80Z/slnGSxaYUuZ1equ7XP0Zxcs1NJ+TqdNUaoSPZ2qyKM/u2DxCz/flwRY +3fkrIz/57IPlqrumKjVcdUReJUMBlqtuam3co0y4sENn39M562DRV3oHDFZ7Tl+IhgAsl6smPxWD +LFuiQXT2wXK5NtrinU5VGbQlcjreiX0/eQjAQhtcNUCwWi+OwtCQgOVy2gbPlWdetK8bCrBc7nh3 +broVpTyB09m6xGURsFxrywcE1oGov/nQgOVyOgadIVrisgxYSFb3IH1h41KXZcBybawcAFi+0VEJ +GiKwXM6iwXHVNs9lIbCQrNiHWpFA9r09+q80RGC5VtYmDlZBdICGCizX2nWDSjPE+sWHCCyXszrm +sbYqiqe/89FclgLLNa8lUbDqV7qsBZZr9mACeJvbYmC55nbEuWFY0s/pFNVYDCy3LUGwfBe7rAaW +syR5rg6sdFkNLFdsZ+io6KesQ3uM5h06sFw1tYmB9aDTcmC5ViQ9Rao7x2U9sNYeiHW40/ob76e7 +LAeW62JfQmDFMlhDCZZzWrJgHV5pQbBim6zGfu7qdC+1IFg1iUwyyvKstCBYrquSBSvfZUWwlsS6 +xtv7id5vrLEgWHUTEwGr3G1FsNY2JTmgYbwlwaqrjToEprMdu4UFFQWxx89oLguC5Zp3IAGwprqs +CFZNeXJgdaywJFiurOiDkwOKZdGWWBKstZ4EwFpiSbBcSSZJm93WBCvaLcP2ELBi5bnWWhIs94PD +F6z85MCqqrMmWBdGM0mOAFexplU0bLQmWAn4k6yl1gRrYnJgLbMoWHN90buEhmL1DGstCtalIw6s +iuEEFus3xFpnUbAulGBZGqwyg6uY4zkkWBKsZMDqNMDySLAkWKkEixcHiTdxVYIlwUoKrGYBVrcE +S4KVUrBE+B77xqgES4KVHFj00ArFK8GSYKUYLF/cEEuCJcFKEiwevndLsCRYqQbLqyhx5r1IsCRY +SYKF4XurBEuClXqwKuONTZZgSbCSBYvFe/yqBEuClTRYtRIsCVY6wGISLAmWBEuCJcGSYEmwMhGs +JRIslFM3phzrOsQ54keHCViz9VFiI11fGe901kiLlW6wwOBJh/zYW10EwwUs0A2wIA5Yn4AVEixL +gAUZBRa+KcE662A5UeZ7xrITN3I6hydYEafD/yewnBKsswqW8xOA0jfRms/RItxM9oo0HMF6lB95 +qVO4c+PM5vKVKyRYaQeLWyYOVo0uIIK7Xa5vGosPDTew6GwEWF8Vp6MjTuKK4WRJsM4SWKYQrEkA +ZKwuIYwESxcu2TS8YqyAVrrcAJNx3RaACUZc9f1S8oEyxjrbYNUA3GEE658nyAqXOodd8B4C1hf0 +vG/Tyq/i/25yiStl8D40MVbIi0K60Emzhm+vcK7xoo5e3CA84b0SrKEBy2m8GId/vxgIroY3WFt4 +wPXo5fxs7pVgnX2wTFdYQ66Qa+MlwxgsdIWbTFco3l5TALl11gJr49xJ+Zfem+nphgIRvF9EXUWA +q3HxWwZYzmEIVmjwjl1BKrl1OYyzFliXGB3Xh1IOVs0NULppoGD54oK1ZlL+TcmBZYby+sO8a8g1 +ziUyWYmCNQlqBgpWd1ywHr08/xpnUnksI91AOQZ3gVii1RTI5z2UIFg3wNI0gvUFgM9sqrkHD6wu +xWBR5kindhwQWNOUKl9MsP7VyB0klXkX6Z6QBOksc22CYH0ZBg4WKNXdMcH6ajBlO/AEKcdpFh3f +lot0I8Ry8UB+ZWJg3aOnE6y6POCPqXlUh9tSDNZFUOz8NBS6BwoWKoytIFiI6t14oNclBlYqFAoW +IZgEWKgwtoJgoXn5TE0BfDIxsFKhULC+gDSmEyxdXLimq9ENr1in67xTXhxYC6V1Bueom/iuOl5y +t8UC69FR8DDyqn87CbDC2AqC9W90OP8Gk4YELPScyYIVxlYQrG9SBP5lXXcOAVho9wrTChZ6F714 +ZRhXSNbdBJzQVdyaBVzHp43VpS6xSaQDDYK1ln6xLaH2ZUBgBdkKgnURXEgxd27dkIB1t2sQYAXZ +CoJ1Azm37+uwaUjA+ow7ra6Qmp74mOcMmq8vQK4bF9H5110CY92uFaDjXl+dh32PFWi9hdm6jbbW +H6qJ6QrX8r1CDeLEhgQU0hIGW0GwdAKrJhTmszuCNBys2fUJnI4adjrEVhCsKwks/BU3DokrdKUZ +LIxkddMerRFm+fuj4A4836uIIKIDadJu4ZcVgja5Tti5c4m90jgxlgnW7CAFSjKq6gMWWAOsS5M6 +neogWJcSWO7MBQvbiiei5xFBhm5Caua6XIaxKuC92eJNLmMtIiiM2uwEwJo1OLCmtVvVYiUFVmXn +yLFYwiNehE5vBeUHuOaGgeW6h/dt9W8PEKw+MVZ3vwqNsYgq68RYfcCa60vgdCCcKtbHFQ5RjJV2 +sJaCkWnCBfeaYA8lHCye7dRhXogrnFwXoCxGr1AfVK/QoCpar7DYZRGwBhS8V3b27RXqQ9Yr7B+s +jsGB9X262y9uDlxWh/ZlFrbUo6VLnSFg1WFHG/faMgrj9jV83GUgeI8Hlisv+TxWkKrwPBbEymPp +ISOv+tOWgn43ASMZmTKwKjti5rH08/rJY9WJzO7Fse8uzU00uz0QsMpaB515N8YifttMUgHkhoIV +SEKQC7oE9JB0Q1ywRJbiNtfAwZrW3h098/7pWJl33XTi/YPljH/bmSs/pWBVdsTIvFOO0ribHBus +uov4uYWl6Psm5VMPVr3SOLgYy8CmeFPwRbEz3BWKtYWbAglS/SZX/2Ald69wWjhVCd4r1EOzpmkD +S9cHDJajsiPuvUK4qr97hV8QRIVb6tSApccDq7Vv+biBBu/OkPkewQkf5n9ha8OWnVHmtwx6dEN3 +UqMbQsCqyZ90zyTRFf3ipPzZnGy0clvmTip9iC+izSO79uiVBcaYjnxw3TPpwltMdC9cEgusCAd0 +dkY3mPcIL9dzuSOnkxK3mddcWZA/9aEgWFvmFly4xEDm0UmznP3dhA7/7gv7lo9THN0jfTxWKFim +uzScfDF/W7y42ozGzFvSfMyMGZ/R3gVmZGAZsG7g8z8CSUdxeDRmRozug3NNsIzzXcvBmgR5mwYJ +VjkFh+0SrFCw9E/y4VaFaylDV8xpKtxIMR+a2Ro+k/DLGDg715iDSOGmGgzfruW4Xc9XWwesOqLl +QmO83Fd1KN1Y8zli7Vu6fq9z4yQaJcPBwrdmbdp4ER9IQxHZeXWDBKuWdzuaRzpYgU4hgkPjBWqM +7u73aaSMDvS83G9yjJwGTNfxZbrhLpb58CyA8wSb1gHLmEEIGh6p8xJ+fM4r521y1XzxXpcxNpnA +cn6Cj17EUP9eAuu8/mOs/sBqNe58jHSwzE5hjRhz5TSGXrnoRxYjsraEgeUU/bxP0p9NZorB2MlS +YGEwdZHRwXZHDrZaczkYYLmN+YRz4bw6BOvewYNlPiGvRLpC0xWGdf4IKmMudBhYhgpNyAywnBYE +ixz4F3XI+3ZY3Qa6HUJpCAOsQCpvVF3MAcoDA8t8Ql7gaQgSrOgWKxwspyFzPoVVLdaauWvNVPZa +d8g0588BxlhiXrRpscwzShFYtYG7Bi0SrABYGGNNDomx+oJ1XUjeMwSsqy0GlrsAxvKFbyFYGGNN +EIHUBMMrfisQY10iDt1IfaYCrNbgXc5aCZYJFvX7Jm+iXmGhKxKsux+l0fPXO7d8EfKvDgPrX83O +oqXSDYUr+QCUUS7R9auhwArByuWnhwwFe4Wue4KT7gcNFgu5f14uwTLBMge7FrrCweKBvlGhxZyo +E7RSYvVtVoqxPgGBCTmBPNb15tLkAozTRR7LeCt3U8rAKguC1T5SwQreJKwxK0TiVT5J55lpfJvW +GbUjt1yuz+aZd9BmG+8Gt3GtmaSXbnLpVgret+B55M9+SBzKlhsgV9xOoCNd6/qEPoGqSNaJt/RL +HxKZ95SAVRvuCeVM6NRpZBe3NYMsn5xiL8FKJVgs1A9KsCRYKQMLg6xpXkWpl2BJsFIKVi09H09R +CiRYEqyUgtVBw2YqFaVj2IJVKcFyWfXJFM2K4hmuYHWoEizLguUz0qPDEawyRYJlWbBoGkL38ASr +Q1HaJFiWBavBvAs97MAqD/ZoJVjWA6tNUaqHJVgdNONLgmXdx8opijoswaJR+yDBsi5YZsJhmIHV +wW8bSLCsC5bHmFMxzMCqCBv+KsGyHljtxpSK4QWWMFhh04wkWNYCywyyhhdYFUbZDAmWdcEygqxh +BVZnn0lGEizLgYVBlne4gWUYLEWVYFkXrHaRyRpOYHUGRlVLsKwLFgZZZRYGa3x0722oNdZJLbMo +WLMzC6wZ/VQtI7CWWBOs/HgGyxyw31cPuq0J1vjkwGq0KFjl8Q66mo9PzppnTbCmxzNYsW/qtFnU +YuUkN26xc601waqPd9Beng/Kml1nRbBqlvWtsuapClTYj3lTp3OpNcGakRxY7BpLgrXCy/qN3rNi +O4+hBGtljKExtXjQVY7Y0Xu3zZpgtSQJlm5JsK7qZPGj9woEy7vUimCNj8GN6BF2x45YKtxWBGui +L0mwqjZaECx3fvyDBsoHZbHxddYDa2NF9ENuDYx8jTkOcK4FwaorYMlqqgXBWtEc/5gr6erPYo0r +rAfW1JhGVunv2tfc1gNrbmfSYE2rsRxYbls/x1xL3cIsxmLxM3RgbVwW02CV9NuRutJyYLnLWfKa +aDmwlnr7OeRmuqmDYLXMsxpYWuwIq/9rv95pNbBs3YMAq3ajxcByl/V3yHj9NxBYrHqltcC6qj2G +7y5XKhJoCsVtLbDmtrPBSK+xFFju/i8Tnm/I4jOqaqwE1opt0Y+3Je6g5JC5bTluK4G1opENTjZL +gTW1td8D7qZ8AweL5TutA9bKZTGvg3gTv0J7hqPd1gFrRfUguWL+8RYC65rdifgMDIUFWKxko1XA +WrouNleJtlFnVG84JGDNa2CDls9mFbDcF7+SyAFTIivLzMQtsQRYdeO9MQNCpXIATbHWEmC5x7ey +FMinbbQEWHVKYuFiuaIEwGItORYAa60tRpqqakBcoZr6HvzZB2tFTgdLjWonuoccLPe8GxPs3lYq +SndW8LJYN945pGDVrc2KYa7aoCDOUJkY7vDGqe4hBcu9IquNpUydkyJGC5xtsNxLshLu3aIZ6MwK +Pfgm29SN7qDG/9ydVm28JuTFivHj26JfEB0l2B1UBu5TOmpzZteEfMPE9J6Ne6or5MXS8eMPs5Sq +Y5ntGudZPJ0lK4LLdUtslw4gaVKtKB1ZEUd/eOvCS01pl6ZZ+ebC3GVN7TFSn94CGidTltxd3I7D +62688mydTsjnL/O2d7LUq+PAA5eetdaZdKG5dOMDLe0DyvHSPZ0sZmV5y8IrpkoNC9VbGqz2anSB +NLSvoE021fBSg6K0WROs1uoCY6xoWUOHbCgJVirUVlUgLBWG7M2SquEoC8ZYLWXGuPYSpT4t8a/U +WVCUXuHQqkpV+FOrobHdJ5tnWIPVaSGwqvjseaVaQjXchS3pswxYbdwH1sugKgNUEXqvcIjlAap7 +JW1VRqjEOmB5MFwvl1hliGiqujXAokExHtkgmQNWpTXA6lQKlGbZHpmijsCYdwsEe9WyPTJGLYrS +aAmwOhKcJSE1PNRIjz2xAlhV5YpXNkfmqIrK21oALF/ch5hIDTuBqN1ghS6hjLAySD5RxmjoD6Q2 +8LhXqUyQl2J3K4BVEO/hOFLDTtV8YvHQg9WtqOWyNTJIojje0IPV2W8xNanhpLYy/pSmoQfLfFyU +VMZ4whargFUrmyPTPKEFwGqjMl1SGdQnrLYGWL7WVpltyByVG7NAs+RPIZVa/yNuo0iwpFKpShG6 +JwCWP4FPC27TM9AD6Ym+m182UUp0tn9HNFhGTftIsDyqkQZXVPEknu3zdVWbsbnvIR+7vUjVFu4j +Jj7MUkm054YiNX/ZUbFnma6WrO6740Gb+IpD+MkzdoiVG0rU/DtPibWAn3B6xCNRFmwIUbniNfy9 +HTOWnYqGz1Pmxo9NdzhmPE1LO8t0rWQ1geXfH/JDB/puqiGyLxum68Ze2BB2beGJnqSP2jRYfcEC +83yA+mpd04FmOQAUHo3Y8KAOqmID/Q90zhqQVNY7Exy4tUYb36/hnhpcH/ndvVOAPyH1VTtk4/tf +o1XT+WcVcupwUaPFkR4Emw3hAA7WBgf+MPjL5L7Ul6tDYGy8gFoL4BvM/4wDf13gv/5+vuj4Qdg+ +KhhCDhabezF2K7afTbRfMmpWppkDVfoBaw7kPO9jPXtzYHLEht+FcSeYbw5chsu7wNbWimIvQu4R +5ltM53PcBt/zs72a43fh++2fAhysro/Aom6210bv/xhmdLL9NvWHjH0JinFRgx9KsMLAegbgEew8 +Hz4f7H3syU4wwPp/GjzP2FOQd5RdADf72c+0vLcYmwn3+tkL2qi3Qvdp5VoOE/zsTQ2ew720vD/j +Vnl7mG8B3JZkBz+kMFB8sF7TdHGBYFP/lEKzqsDQ9NunP0BZC8jhkF0mVl4BtPLvNvt77ECFfhoN +cRasY69WVf2ZsWMPVG1lbL4KYzlYf9X0dxgxtYx15ehv0Lm+3clYNizjX75MghUG1vlGY6O9vxr/ +q68KFs6cDo5csfH2+dl+P+tVoY3RP8b//tNGdCFev2QfPFBFrbihqlLEXm/qo470sGa+F277CrsL +rsPVv9Wy30s21RAYABUfrP+A85iJzE18ZUSS/H9hHP49Bx7Y+WATIyyqxb7/bYTk7+fA91jvR8je +fRZGY3ygaM+3cbBahUNshQlo3EazXdVbT9DrL0EpWjObtFjhYP0JHCeE2/sOjMKlSgiOCFFK9wVf +4m/+Tw3eRouFru9Nsli/EJgsh2sZ+wrkveV/hlsoxmF7OriXDfagg/olo0U0XkmoUVEcLDZYjuoq +VLWDwPo4PBIgaAKdQ8SQvJOj4BbGPrBxb134FvsYt1hdWfC4scHPwP4Gt3dPvyhsXpvfQOqvoNP5 +vgpj0XgVLnAAOOgsj+fAwqrpUCxjLHBU8YYAAus7kG108Dg2vC6xqbfDOUN6sk+xF2z6sgd53PSE +2HUVNWDXGDj3Q53bPGGZToXu9Q4bA1TGvZeM18DVGlYhry9YATWQBdpqrBc+L0IY2tuPoMO0QfHu +XWSW/gPGYn/uZQ0M/l6wwSLGY8J8HS41D4CDhTHYN/hFo7EDALk7WpaDg8h7ir46SoQ68sAKCFur +IkiOg8CKzB6FgLUe4EcijgcYi+A8KN6rogb0v4DRP2QbUdocvqHQUxpZL7sgKimwOsLnhvYFS21t +QbUqkWCN7vNRJ6eA/izFbIep8uwhjNNP5kBh1e06YGBF9vUZJI5fEyfRpuW+EwYWGjO0TWXAwdJ/ +YnrB+0Hb0XKfpv9UgmU0BJbt7hUAAAvPSURBVAfr9gTB6mH3YVfQTxfs2N0tMyHnRBhYgrdfi23f +tI06Yu613gGz/ATW7mTBosA9dJRK/BjrioAr/HEg2gro2BSw/zokjZAFm9mhMQ5wzLoCAys8WrwK +ik+ZfUhhukLAIuwge7M2Dl2h6udeMZcds+m/YRTbTZZghcZYQVf4N97TiwFWD4ZScIuf+of2oxyj +O4KukDfgnzQ0WGKn++BfTK7uEnsZrrCLwq2BclUWMayuv+D9XAqH9jGMnh6J5KoIcvaF5dyA0qgH +WtrYKP13wrpeb/wax5AhnvEKBYsda209cQBmoVfkYB1AsA6I9w6AJsEKBetvGFmh/3qeneERVEyL +tRx0Ho+vMs2UzQze74LPi3hdJKy4J/ylsTty9XjIqn/mDDh471SVaeGPkowP1n4bueHP2m/ZzoPw +sPhqCow10J9TcgsPmvTfdXqf9NNSDv7FaP0b5hUxEwp1yPf7Q8HyNnq4Kfsa682B33CjeC6F9PQ9 +f8SQXoIVmm6YQhmdX6jFe3X4AYsJ1nrIEx2+JwR+y9FMYdeKTNwF8HsRwY4FnduDDwJ9P1z5U9OI +kVn7Hy17gLeC2qgGY/cAwMIj1Vef6L0PIz5+U6eq2hsSIy6sRlVRj1HfwY4tQPd1yIbo49LX0Bzl +QC69X+2hcEr/DfYMbw6zWN+F/CNsly33HT++n7+H4U/2DdaVQ51LXFwowQoD600NFu5hL4MOY6nR +G6qrooCFG43lv3n7u7nwtVNsu07x1AIoPYHNRR7wXR1uRotAeR/yliLqfTPX2KsNwy7HDnZwSqBT +n3DCXVGmRVSC7wcsdp8GqupA+5m/2R+ax3rfZnRZcPNetK+qCqOPUOxNS6V+sj+GqsgRLqLrwnCG +Aiw/kqerDpVHaYtpEQr93EbS92knJFjht3RetuMPw2/E3HkkIr8QeLnA/M3bKIClrSkWOa7TIv+h +MZo/RVc/XeL/CdmnTUcYuLuznpobxp0a0KFWRnvQUVbfJJcBliJuQr/+WJGiPdAyBfLeCM1jeRVT +9GpXmZK/mTqxPTunKzOa6Jo6x3y/qmuMMprWzFFs7xn5DhFi3We33WkEorumK8U7uP099mQRLp4a +6VyxacGGEMmhY9vLsm0Ln7/LQb6wPHzKXIV4+RHzN8de+sFVevaM53lO9dgG3XYnub/1ikJ5nKcU +Bd3ig+ZHBPYib7R3fnb+5u6B3IRudSjRxgAnPGxm552Jf5c/ua3kWJlE9PpMS111vHJslEc8yIF+ +UoNQgwLoBqOVYpRgSSWtRipIDC1R35NgSSWn7lpR5zpG5VgJllQyaq0UPbOYTw+RYEkNWG314sE0 +1XHm7UmwpAYkX3MlUkUpBk/c8ukSLKmE1d5YaT7ur7q/h0hKsKT6V2erp7qiIJATr27t/0m+Eiyp +aGrxNjd7GmurqyrLSxziOX9Clc2JPUdZgiUVTaBECFeU17Yk/nBuCZZUNBWEMFVQUe1paRvgY0kl +WFJRXSEfFt3W3pHsY24lWFJpkQRLSoIlJcGSkmBJSUmwpCRYUhIsKak0g9Vab0zwqq3nQ057vQ1b +m96OuuvL9XySoZ+1NG7b7RcTO7z1TebErdcbt/WtAHAwuPJg49am4LQA39Z62RgRqq8X2UmP0SYH +Guu3RS+q8O5WsQW2RQNuwtuCWiV2U9TWG2o3WlDs5e/11jeeSAdYEfMKt9tpTqFaGuW7juXwSYb+ +Y9NVAIe2B49rfx5ubeNzvHuX22i/8FqiYmXhW+Yi2AKVMReb8+6lAnKAGEgnSs3sn0KzCtXRf4iy +5QLRav69OpWDKj7Rw96fSa0yms95vs/GV4btEVIq0r+3iO91BFvwNWpB5fG0g/WyBouamh+zw8V9 +djw5EzhYvRdA/jbPdBj9Hk1MLW3aYHM820OgFDY9aaPqWSFaD7lbPTMh30+Tox2rmxeICfWMV0KU +YMUF630dxm1tbiwC+9tnIjdcr4lWw20ubmoEGOdH1OybPUU0PxV/dftWXDw3bHaduAuoQd4+KpqF +exXBuNO0iC2oOX6fbrCuAF71+GUtL6KSKNuZBwKs12xU1eGkDb7HvstrxPyWivy9puHJsf+dsSh0 +n+M2eBZJ/Bh87wz7GE2O7rIZ5R0O2SRY/YD1HbATGb1TqDJfmF6badYg/Y5qP2HU8RtFk+vf1ahg +5Bh4iTO3L5qlQ+P0Pzaaa/+uLW8PewJoavEGXmQvrWBlGzVmmprbOOWBQpFesD+icrA6W71i82qE +ZR1dNlRR9Me8tB93f3OU0afRrimj/X8FlVzji8TUOXyDLF40mfk+kvusBCs+WBVGISNvM9XkDJ0J +rUDpjaLV2luahZtrYzq0MlGN9C/aqKN+ciE/YF15Ctqt9/lf0lNU25YdNveiGqQPMdbzF9uod9IM +1q2Qu/lEyBkEAuzdq98KK0iKJucniOE6sdkP0dT98LEi28I96PePU6mAn4H+UmjZUVxRfITt0kQN +m8Xw+AEJVhSwOoNg/QrgzmAEHlq7YeHz4aUcXgC0WAvgslOiEsh/CiKpGhYV9HuWikKKNv1wlB60 +Yi9Q1eSP8zJGH+bk/SENYBlDvHipyIPZ6KJmrDNOyNPcGuamg2D1ziS/fgUPqdArbkbzS1Xewf4c +vy7053gditc0HlL9GHLxstgAdkXTnhMBVilrk2BFActsCsJmOjaFtszoSHubPaFbhoJ1vIjs0MkF +oCowDsF5DLJp9SpeknEBZG/XzKJF60OK6Z2cQnvpyVf0GxhY7OAC6rw5tOei7BoEqxej8F9TKObY +wU4uB/SK2aA/z3z3UUjPus7BjyhGJ9h7Dsw4wfbmIEPYl8TvUeFOvx+tXf5pCVa/YPVu4D05ZXWU +EhchYCFXo45QTw93duAl7g+UiqSm/ruOH2E4wt4xwcJ9yNWofURUiwBrd7rTDeiBPbdnO0B9Lg5Y +vpmgPm3UKcSzKcLTGWUaLyqrvV8Dx0uUJTmETClU8IhgW3SKvf4R3OzkmFw8pXYJVnxXSL+z97E8 +ozRRTLAO6ZCNsfoHOmz2U52xl9BiKUGLRUXW7EdEzvG3WraZDTpWJKp+ptVihYPFj2Hv+dH6CSZY +vinC5VFfcboyY88V8N/oFY2C7xR1vaoB/Jp/0LFVDu2BV7QJ9PiAf/A4fhzaKsgm4wVKhWQpTh5L +6PBiyDsRGyzkitfvNAKr5RhYhcRYIq+jG2DdBXeYNOZBDjdeIsb6IMk674mDdWDVFNE92AW2mGCh +FdVCe7JdOXazV9ibRVVuu8ag+R0d7Ge8CnMpjqezfR00AstQpWQpNliPlf1cOLB4VZOP6/QgGhao +wb0Kctifgr1CwxUaddXGmHYJvee4I0aamnqFf7LZ09wrxL7encYXxrZYiyHXeKbPX8vz3qFIazLF +6WOPUoVu9Q1ebnKHqPf+lRL6Owc7kGixqMb4rTCZdXhI9eBo9kqWYoM1nUprM+pOx7FYRfBR4Sd/ +oelHeMD/eQLo14E8lgjeeWb9bwG7NF2Un2QskMc6L915rPsBCmsbn5wOKsVIEU8F52Cd2asZ4X41 +FRDN3/aY3f4Sz7xrW58cBbPQQFEW9Ble1f5F0Fc3zOePnVhMi7drjh8ZaWQZvPcD1ssOyFm3rWG5 +g9d5jKjoJ8A6Qw9fEBX9eqfg1g0XYBx/hjLv6xpE5v1n1CP8iqhua1RTZmeeMffyknOZsW2VI/2Z +994N2fxeofZ8RB4raLG+ZDoyDKr2Z9P9Px5v9S7HqEmddYr6HsXcNo0+KlbaZ5GB66EbWJD9tPlh +Eqz+YqxdOvUKHaJXGL0G6cxgDdJj/F5hDm+39XRfgyruoyO8mSfvP3oq8CgU8iDB24YH6bah8jRL +PVhtnkax0OjhSavelmZPc1vYKlONnhb+1xC96PV6dpsjFl5vbqL9Xvd46Kazr8lDHY4DYiXpIG4b +NOroECVJkRe5R/QKvUabHPB6ml45FbbKkPHSbApPB/+pPa8YHu5gcxMfvOD1eGj31zweDNNagi1t +iM9GbfE0p2V0g5QUk2BJSbCkJFhSUoPW/wfr5tj8wgE+HwAAAABJRU5ErkJggg== diff --git a/Documentation/DocBook/v4l/.gitignore b/Documentation/DocBook/media/v4l/.gitignore similarity index 100% rename from Documentation/DocBook/v4l/.gitignore rename to Documentation/DocBook/media/v4l/.gitignore diff --git a/Documentation/DocBook/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml similarity index 100% rename from Documentation/DocBook/v4l/biblio.xml rename to Documentation/DocBook/media/v4l/biblio.xml diff --git a/Documentation/DocBook/v4l/capture.c.xml b/Documentation/DocBook/media/v4l/capture.c.xml similarity index 100% rename from Documentation/DocBook/v4l/capture.c.xml rename to Documentation/DocBook/media/v4l/capture.c.xml diff --git a/Documentation/DocBook/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml similarity index 99% rename from Documentation/DocBook/v4l/common.xml rename to Documentation/DocBook/media/v4l/common.xml index 9028721438dc3625cce32fba512c715ab38f337f..a86f7a04552914a5a460096703cc721dcdebc055 100644 --- a/Documentation/DocBook/v4l/common.xml +++ b/Documentation/DocBook/media/v4l/common.xml @@ -236,7 +236,15 @@ important parts of the API. The &VIDIOC-QUERYCAP; ioctl is available to check if the kernel device is compatible with this specification, and to query the functions and I/O -methods supported by the device. Other features can be queried +methods supported by the device. + + Starting with kernel version 3.1, VIDIOC-QUERYCAP will return the +V4L2 API version used by the driver, with generally matches the Kernel version. +There's no need of using &VIDIOC-QUERYCAP; to check if an specific ioctl is +supported, the V4L2 core now returns ENOIOCTLCMD if a driver doesn't provide +support for an ioctl. + + Other features can be queried by calling the respective ioctl, for example &VIDIOC-ENUMINPUT; to learn about the number, types and names of video connectors on the device. Although abstraction is a major objective of this API, the diff --git a/Documentation/DocBook/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml similarity index 99% rename from Documentation/DocBook/v4l/compat.xml rename to Documentation/DocBook/media/v4l/compat.xml index 9f7cd4f2579220f08082bd91d79dc04bd65fcd5a..ce1004a7da5233f96d1a33636a11b24879ae69a1 100644 --- a/Documentation/DocBook/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -10,12 +10,10 @@ driver writers to port or update their code. The Video For Linux API was first introduced in Linux 2.1 to unify and replace various TV and radio device related interfaces, developed independently by driver writers in prior years. Starting -with Linux 2.5 the much improved V4L2 API replaces the V4L API, -although existing drivers will continue to support V4L applications in -the future, either directly or through the V4L2 compatibility layer in -the videodev kernel module translating ioctls on -the fly. For a transition period not all drivers will support the V4L2 -API. +with Linux 2.5 the much improved V4L2 API replaces the V4L API. +The support for the old V4L calls were removed from Kernel, but the +library supports the conversion of a V4L +API system call into a V4L2 one.
Opening and Closing Devices @@ -84,12 +82,7 @@ not compatible with V4L or V4L2. , device file. V4L2 drivers may support multiple opens, see for details and consequences. - V4L drivers respond to V4L2 ioctls with an &EINVAL;. The -compatibility layer in the V4L2 videodev module -can translate V4L ioctl requests to their V4L2 counterpart, however a -V4L2 driver usually needs more preparation to become fully V4L -compatible. This is covered in more detail in . + V4L drivers respond to V4L2 ioctls with an &EINVAL;.
@@ -2367,6 +2360,16 @@ that used it. It was originally scheduled for removal in 2.6.35.
+
+ V4L2 in Linux 3.1 + + + VIDIOC_QUERYCAP now returns a per-subsystem version instead of a per-driver one. + Standardize an error code for invalid ioctl. + Added V4L2_CTRL_TYPE_BITMASK. + + +
Relation of V4L2 to other Linux multimedia APIs @@ -2472,6 +2475,9 @@ ioctls. &VIDIOC-DBG-G-CHIP-IDENT; ioctl. + + Flash API. +
diff --git a/Documentation/DocBook/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml similarity index 62% rename from Documentation/DocBook/v4l/controls.xml rename to Documentation/DocBook/media/v4l/controls.xml index a920ee80f640608d5f0b94f51f5dca682c2a5303..85164016ed26c28e736651cd4c7199224ed503a6 100644 --- a/Documentation/DocBook/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -51,6 +51,10 @@ readability until any ioctl (querying the properties) is called. + + All controls use machine endianness. + + Control IDs @@ -323,6 +327,22 @@ minimum value disables backlight compensation. End of the predefined control IDs (currently V4L2_CID_ILLUMINATORS_2 + 1). + + + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE + integer + This is a read-only control that can be read by the application +and used as a hint to determine the number of CAPTURE buffers to pass to REQBUFS. +The value is the minimum number of CAPTURE buffers that is necessary for hardware +to work. + + + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT + integer + This is a read-only control that can be read by the application +and used as a hint to determine the number of OUTPUT buffers to pass to REQBUFS. +The value is the minimum number of OUTPUT buffers that is necessary for hardware +to work. V4L2_CID_PRIVATE_BASE @@ -545,6 +565,10 @@ may not be supported (VIDIOC_QUERYMENU will return an error). A good example is the list of supported MPEG audio bitrates. Some drivers only support one or two bitrates, others support a wider range. + + + All controls use machine endianness. +
@@ -670,7 +694,8 @@ caption of a Tab page in a GUI, for example. The MPEG-1, -2 or -4 output stream type. One cannot assume anything here. Each hardware MPEG encoder tends to support different subsets of the available MPEG -stream types. The currently defined stream types are: +stream types. This control is specific to multiplexed MPEG streams. +The currently defined stream types are: @@ -800,6 +825,7 @@ frequency. Possible values are: V4L2_CID_MPEG_AUDIO_ENCODING  enum v4l2_mpeg_audio_encoding MPEG Audio encoding. +This control is specific to multiplexed MPEG streams. Possible values are: @@ -1250,7 +1276,8 @@ and reproducible audio bitstream. 0 = unmuted, 1 = muted. V4L2_CID_MPEG_VIDEO_ENCODING  enum v4l2_mpeg_video_encoding MPEG Video encoding -method. Possible values are: +method. This control is specific to multiplexed MPEG streams. +Possible values are: @@ -1406,225 +1433,1178 @@ of the video. The supplied 32-bit integer is interpreted as follows (bit - - -
-
-
- CX2341x MPEG Controls - The following MPEG class controls deal with MPEG -encoding settings that are specific to the Conexant CX23415 and -CX23416 MPEG encoding chips. + + + V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE  + boolean + + If enabled the decoder expects to receive a single slice per buffer, otherwise +the decoder expects a single frame in per buffer. Applicable to the decoder, all codecs. + + - - CX2341x Control IDs - - - - - - - - + - ID - Type - Description + V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE  + boolean - - + Enable writing sample aspect ratio in the Video Usability Information. +Applicable to the H264 encoder. + + - - V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE  - enum v4l2_mpeg_cx2341x_video_spatial_filter_mode - Sets the Spatial -Filter mode (default MANUAL). Possible values -are: + + V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC  + enum v4l2_mpeg_video_h264_vui_sar_idc + + VUI sample aspect ratio indicator for H.264 encoding. The value +is defined in the table E-1 in the standard. Applicable to the H264 encoder. - - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL  - Choose the filter manually - - - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO  - Choose the filter automatically - + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED  + Unspecified + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1  + 1x1 + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11  + 12x11 + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11  + 10x11 + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11  + 16x11 + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33  + 40x33 + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11  + 24x11 + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11  + 20x11 + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11  + 32x11 + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33  + 80x33 + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11  + 18x11 + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11  + 15x11 + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33  + 64x33 + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99  + 160x99 + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3  + 4x3 + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2  + 3x2 + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1  + 2x1 + + + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED  + Extended SAR + + - V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER  - integer (0-15) - The setting for the -Spatial Filter. 0 = off, 15 = maximum. (Default is 0.) + V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH  + integer + Extended sample aspect ratio width for H.264 VUI encoding. +Applicable to the H264 encoder. + + - - V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE  - enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type - Select the algorithm -to use for the Luma Spatial Filter (default -1D_HOR). Possible values: + + V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT  + integer + + Extended sample aspect ratio height for H.264 VUI encoding. +Applicable to the H264 encoder. + + + + + V4L2_CID_MPEG_VIDEO_H264_LEVEL  + enum v4l2_mpeg_video_h264_level + + The level information for the H264 video elementary stream. +Applicable to the H264 encoder. +Possible values are: - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF  - No filter + V4L2_MPEG_VIDEO_H264_LEVEL_1_0  + Level 1.0 - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR  - One-dimensional horizontal + V4L2_MPEG_VIDEO_H264_LEVEL_1B  + Level 1B - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT  - One-dimensional vertical + V4L2_MPEG_VIDEO_H264_LEVEL_1_1  + Level 1.1 - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE  - Two-dimensional separable + V4L2_MPEG_VIDEO_H264_LEVEL_1_2  + Level 1.2 - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE  - Two-dimensional symmetrical -non-separable + V4L2_MPEG_VIDEO_H264_LEVEL_1_3  + Level 1.3 + + + V4L2_MPEG_VIDEO_H264_LEVEL_2_0  + Level 2.0 + + + V4L2_MPEG_VIDEO_H264_LEVEL_2_1  + Level 2.1 + + + V4L2_MPEG_VIDEO_H264_LEVEL_2_2  + Level 2.2 + + + V4L2_MPEG_VIDEO_H264_LEVEL_3_0  + Level 3.0 + + + V4L2_MPEG_VIDEO_H264_LEVEL_3_1  + Level 3.1 + + + V4L2_MPEG_VIDEO_H264_LEVEL_3_2  + Level 3.2 + + + V4L2_MPEG_VIDEO_H264_LEVEL_4_0  + Level 4.0 + + + V4L2_MPEG_VIDEO_H264_LEVEL_4_1  + Level 4.1 + + + V4L2_MPEG_VIDEO_H264_LEVEL_4_2  + Level 4.2 + + + V4L2_MPEG_VIDEO_H264_LEVEL_5_0  + Level 5.0 + + + V4L2_MPEG_VIDEO_H264_LEVEL_5_1  + Level 5.1 + - - V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE  - enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type - Select the algorithm -for the Chroma Spatial Filter (default 1D_HOR). + + V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL  + enum v4l2_mpeg_video_mpeg4_level + + The level information for the MPEG4 elementary stream. +Applicable to the MPEG4 encoder. Possible values are: - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF  - No filter + V4L2_MPEG_VIDEO_LEVEL_0  + Level 0 - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR  - One-dimensional horizontal + V4L2_MPEG_VIDEO_LEVEL_0B  + Level 0b + + + V4L2_MPEG_VIDEO_LEVEL_1  + Level 1 + + + V4L2_MPEG_VIDEO_LEVEL_2  + Level 2 + + + V4L2_MPEG_VIDEO_LEVEL_3  + Level 3 + + + V4L2_MPEG_VIDEO_LEVEL_3B  + Level 3b + + + V4L2_MPEG_VIDEO_LEVEL_4  + Level 4 + + + V4L2_MPEG_VIDEO_LEVEL_5  + Level 5 + - - V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE  - enum v4l2_mpeg_cx2341x_video_temporal_filter_mode - Sets the Temporal -Filter mode (default MANUAL). Possible values -are: + + V4L2_CID_MPEG_VIDEO_H264_PROFILE  + enum v4l2_mpeg_h264_profile + + The profile information for H264. +Applicable to the H264 encoder. +Possible values are: - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL  - Choose the filter manually + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE  + Baseline profile - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO  - Choose the filter automatically + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE  + Constrained Baseline profile + + + V4L2_MPEG_VIDEO_H264_PROFILE_MAIN  + Main profile + + + V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED  + Extended profile + + + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH  + High profile + + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10  + High 10 profile + + + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422  + High 422 profile + + + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE  + High 444 Predictive profile + + + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA  + High 10 Intra profile + + + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA  + High 422 Intra profile + + + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA  + High 444 Intra profile + + + V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA  + CAVLC 444 Intra profile + + + V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE  + Scalable Baseline profile + + + V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH  + Scalable High profile + + + V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA  + Scalable High Intra profile + + + V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH  + Stereo High profile + + + V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH  + Multiview High profile + + + - V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER  - integer (0-31) - The setting for the -Temporal Filter. 0 = off, 31 = maximum. (Default is 8 for full-scale -capturing and 0 for scaled capturing.) + V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE  + enum v4l2_mpeg_mpeg4_profile - - - V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE  - enum v4l2_mpeg_cx2341x_video_median_filter_type - Median Filter Type -(default OFF). Possible values are: + The profile information for MPEG4. +Applicable to the MPEG4 encoder. +Possible values are: - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF  - No filter + V4L2_MPEG_VIDEO_PROFILE_SIMPLE  + Simple profile - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR  - Horizontal filter + V4L2_MPEG_VIDEO_PROFILE_ADVANCED_SIMPLE  + Advanced Simple profile - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT  - Vertical filter + V4L2_MPEG_VIDEO_PROFILE_CORE  + Core profile - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT  - Horizontal and vertical filter + V4L2_MPEG_VIDEO_PROFILE_SIMPLE_SCALABLE  + Simple Scalable profile - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG  - Diagonal filter + V4L2_MPEG_VIDEO_PROFILE_ADVANCED_CODING_EFFICIENCY  + + - V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM  - integer (0-255) - Threshold above which -the luminance median filter is enabled (default 0) + V4L2_CID_MPEG_VIDEO_MAX_REF_PIC  + integer + + The maximum number of reference pictures used for encoding. +Applicable to the encoder. + + - V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP  - integer (0-255) - Threshold below which -the luminance median filter is enabled (default 255) + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE  + enum v4l2_mpeg_multi_slice_mode + + Determines how the encoder should handle division of frame into slices. +Applicable to the encoder. +Possible values are: - - V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM  - integer (0-255) - Threshold above which -the chroma median filter is enabled (default 0) + + + + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE  + Single slice per frame. + + + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB  + Multiple slices with set maximum number of macroblocks per slice. + + + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES  + Multiple slice with set maximum size in bytes per slice. + + + + - V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP  - integer (0-255) - Threshold below which -the chroma median filter is enabled (default 255) + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB  + integer + The maximum number of macroblocks in a slice. Used when +V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE is set to V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB. +Applicable to the encoder. + + - V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS  - boolean + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES  + integer - The CX2341X MPEG encoder -can insert one empty MPEG-2 PES packet into the stream between every -four video frames. The packet size is 2048 bytes, including the -packet_start_code_prefix and stream_id fields. The stream_id is 0xBF -(private stream 2). The payload consists of 0x00 bytes, to be filled -in by the application. 0 = do not insert, 1 = insert packets. + The maximum size of a slice in bytes. Used when +V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE is set to V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES. +Applicable to the encoder. - + + + + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE  + enum v4l2_mpeg_h264_loop_filter_mode + + Loop filter mode for H264 encoder. +Possible values are: + + + + + + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED  + Loop filter is enabled. + + + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED  + Loop filter is disabled. + + + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY  + Loop filter is disabled at the slice boundary. + + + + + + + + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA  + integer + + Loop filter alpha coefficient, defined in the H264 standard. +Applicable to the H264 encoder. + + + + + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA  + integer + + Loop filter beta coefficient, defined in the H264 standard. +Applicable to the H264 encoder. + + + + + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE  + enum v4l2_mpeg_h264_symbol_mode + + Entropy coding mode for H264 - CABAC/CAVALC. +Applicable to the H264 encoder. +Possible values are: + + + + + + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC  + Use CAVLC entropy coding. + + + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC  + Use CABAC entropy coding. + + + + + + + + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM  + boolean + + Enable 8X8 transform for H264. Applicable to the H264 encoder. + + + + + V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB  + integer + + Cyclic intra macroblock refresh. This is the number of continuous macroblocks +refreshed every frame. Each frame a succesive set of macroblocks is refreshed until the cycle completes and starts from the +top of the frame. Applicable to H264, H263 and MPEG4 encoder. + + + + + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE  + boolean + + Frame level rate control enable. +If this control is disabled then the quantization parameter for each frame type is constant and set with appropriate controls +(e.g. V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP). +If frame rate control is enabled then quantization parameter is adjusted to meet the chosen bitrate. Minimum and maximum value +for the quantization parameter can be set with appropriate controls (e.g. V4L2_CID_MPEG_VIDEO_H263_MIN_QP). +Applicable to encoders. + + + + + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE  + boolean + + Macroblock level rate control enable. +Applicable to the MPEG4 and H264 encoders. + + + + + V4L2_CID_MPEG_VIDEO_MPEG4_QPEL  + boolean + + Quarter pixel motion estimation for MPEG4. Applicable to the MPEG4 encoder. + + + + + V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP  + integer + + Quantization parameter for an I frame for H263. Valid range: from 1 to 31. + + + + + V4L2_CID_MPEG_VIDEO_H263_MIN_QP  + integer + + Minimum quantization parameter for H263. Valid range: from 1 to 31. + + + + + V4L2_CID_MPEG_VIDEO_H263_MAX_QP  + integer + + Maximum quantization parameter for H263. Valid range: from 1 to 31. + + + + + V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP  + integer + + Quantization parameter for an P frame for H263. Valid range: from 1 to 31. + + + + + V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP  + integer + + Quantization parameter for an B frame for H263. Valid range: from 1 to 31. + + + + + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP  + integer + + Quantization parameter for an I frame for H264. Valid range: from 0 to 51. + + + + + V4L2_CID_MPEG_VIDEO_H264_MIN_QP  + integer + + Minimum quantization parameter for H264. Valid range: from 0 to 51. + + + + + V4L2_CID_MPEG_VIDEO_H264_MAX_QP  + integer + + Maximum quantization parameter for H264. Valid range: from 0 to 51. + + + + + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP  + integer + + Quantization parameter for an P frame for H264. Valid range: from 0 to 51. + + + + + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP  + integer + + Quantization parameter for an B frame for H264. Valid range: from 0 to 51. + + + + + V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP  + integer + + Quantization parameter for an I frame for MPEG4. Valid range: from 1 to 31. + + + + + V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP  + integer + + Minimum quantization parameter for MPEG4. Valid range: from 1 to 31. + + + + + V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP  + integer + + Maximum quantization parameter for MPEG4. Valid range: from 1 to 31. + + + + + V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP  + integer + + Quantization parameter for an P frame for MPEG4. Valid range: from 1 to 31. + + + + + V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP  + integer + + Quantization parameter for an B frame for MPEG4. Valid range: from 1 to 31. + + + + + V4L2_CID_MPEG_VIDEO_VBV_SIZE  + integer + + The Video Buffer Verifier size in kilobytes, it is used as a limitation of frame skip. +The VBV is defined in the standard as a mean to verify that the produced stream will be succesfully decoded. +The standard describes it as "Part of a hypothetical decoder that is conceptually connected to the +output of the encoder. Its purpose is to provide a constraint on the variability of the data rate that an +encoder or editing process may produce.". +Applicable to the MPEG1, MPEG2, MPEG4 encoders. + + + + + V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE  + integer + + The Coded Picture Buffer size in kilobytes, it is used as a limitation of frame skip. +The CPB is defined in the H264 standard as a mean to verify that the produced stream will be succesfully decoded. +Applicable to the H264 encoder. + + + + + V4L2_CID_MPEG_VIDEO_H264_I_PERIOD  + integer + + Period between I-frames in the open GOP for H264. In case of an open GOP +this is the period between two I-frames. The period between IDR (Instantaneous Decoding Refresh) frames is taken from the GOP_SIZE control. +An IDR frame, which stands for Instantaneous Decoding Refresh is an I-frame after which no prior frames are +referenced. This means that a stream can be restarted from an IDR frame without the need to store or decode any +previous frames. Applicable to the H264 encoder. + + + + + V4L2_CID_MPEG_VIDEO_HEADER_MODE  + enum v4l2_mpeg_header_mode + + Determines whether the header is returned as the first buffer or is +it returned together with the first frame. Applicable to encoders. +Possible values are: + + + + + + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE  + The stream header is returned separately in the first buffer. + + + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME  + The stream header is returned together with the first encoded frame. + + + + + + + V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER  + boolean + Enabled the deblocking post processing filter for MPEG4 decoder. +Applicable to the MPEG4 decoder. + + + + V4L2_CID_MPEG_VIDEO_MPEG4_VOP_TIME_RES  + integer + vop_time_increment_resolution value for MPEG4. Applicable to the MPEG4 encoder. + + + + V4L2_CID_MPEG_VIDEO_MPEG4_VOP_TIME_INC  + integer + vop_time_increment value for MPEG4. Applicable to the MPEG4 encoder. + + + + +
+
+ +
+ MFC 5.1 MPEG Controls + + The following MPEG class controls deal with MPEG +decoding and encoding settings that are specific to the Multi Format Codec 5.1 device present +in the S5P family of SoCs by Samsung. + + + + MFC 5.1 Control IDs + + + + + + + + + + ID + Type + Description + + + + + + V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE  + integer + If the display delay is enabled then the decoder has to return a +CAPTURE buffer after processing a certain number of OUTPUT buffers. If this number is low, then it may result in +buffers not being dequeued in display order. In addition hardware may still use those buffers as reference, thus +application should not write to those buffers. This feature can be used for example for generating thumbnails of videos. +Applicable to the H264 decoder. + + + + + V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY  + integer + Display delay value for H264 decoder. +The decoder is forced to return a decoded frame after the set 'display delay' number of frames. If this number is +low it may result in frames returned out of dispaly order, in addition the hardware may still be using the returned buffer +as a reference picture for subsequent frames. + + + + + V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P  + integer + The number of reference pictures used for encoding a P picture. +Applicable to the H264 encoder. + + + + V4L2_CID_MPEG_MFC51_VIDEO_PADDING  + boolean + Padding enable in the encoder - use a color instead of repeating border pixels. +Applicable to encoders. + + + + V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV  + integer + Padding color in the encoder. Applicable to encoders. The supplied 32-bit integer is interpreted as follows (bit +0 = least significant bit): + + + + + + Bit 0:7 + V chrominance information + + + Bit 8:15 + U chrominance information + + + Bit 16:23 + Y luminance information + + + Bit 24:31 + Must be zero. + + + + + + + V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF  + integer + Reaction coefficient for MFC rate control. Applicable to encoders. +Note 1: Valid only when the frame level RC is enabled. +Note 2: For tight CBR, this field must be small (ex. 2 ~ 10). +For VBR, this field must be large (ex. 100 ~ 1000). +Note 3: It is not recommended to use the greater number than FRAME_RATE * (10^9 / BIT_RATE). + + + + + V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK  + boolean + Adaptive rate control for dark region. +Valid only when H.264 and macroblock level RC is enabled (V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE). +Applicable to the H264 encoder. + + + + V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH  + boolean + Adaptive rate control for smooth region. +Valid only when H.264 and macroblock level RC is enabled (V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE). +Applicable to the H264 encoder. + + + + V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC  + boolean + Adaptive rate control for static region. +Valid only when H.264 and macroblock level RC is enabled (V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE). +Applicable to the H264 encoder. + + + + V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY  + boolean + Adaptive rate control for activity region. +Valid only when H.264 and macroblock level RC is enabled (V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE). +Applicable to the H264 encoder. + + + + V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE  + enum v4l2_mpeg_mfc51_frame_skip_mode + + +Indicates in what conditions the encoder should skip frames. If encoding a frame would cause the encoded stream to be larger then +a chosen data limit then the frame will be skipped. +Possible values are: + + + + + + V4L2_MPEG_MFC51_FRAME_SKIP_MODE_DISABLED  + Frame skip mode is disabled. + + + V4L2_MPEG_MFC51_FRAME_SKIP_MODE_LEVEL_LIMIT  + Frame skip mode enabled and buffer limit is set by the chosen level and is defined by the standard. + + + V4L2_MPEG_MFC51_FRAME_SKIP_MODE_BUF_LIMIT  + Frame skip mode enabled and buffer limit is set by the VBV (MPEG1/2/4) or CPB (H264) buffer size control. + + + + + + + V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT  + integer + Enable rate-control with fixed target bit. +If this setting is enabled, then the rate control logic of the encoder will calculate the average bitrate +for a GOP and keep it below or equal the set bitrate target. Otherwise the rate control logic calculates the +overall average bitrate for the stream and keeps it below or equal to the set bitrate. In the first case +the average bitrate for the whole stream will be smaller then the set bitrate. This is caused because the +average is calculated for smaller number of frames, on the other hand enabling this setting will ensure that +the stream will meet tight bandwidth contraints. Applicable to encoders. + + + + + V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE  + enum v4l2_mpeg_mfc51_force_frame_type + + Force a frame type for the next queued buffer. Applicable to encoders. +Possible values are: + + + + + + V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_DISABLED  + Forcing a specific frame type disabled. + + + V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_I_FRAME  + Force an I-frame. + + + V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_NOT_CODED  + Force a non-coded frame. + + + + + + +
+
+ +
+ CX2341x MPEG Controls + + The following MPEG class controls deal with MPEG +encoding settings that are specific to the Conexant CX23415 and +CX23416 MPEG encoding chips. + + + CX2341x Control IDs + + + + + + + + + + ID + Type + Description + + + + + + V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE  + enum v4l2_mpeg_cx2341x_video_spatial_filter_mode + Sets the Spatial +Filter mode (default MANUAL). Possible values +are: + + + + + + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL  + Choose the filter manually + + + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO  + Choose the filter automatically + + + + + + + V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER  + integer (0-15) + The setting for the +Spatial Filter. 0 = off, 15 = maximum. (Default is 0.) + + + + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE  + enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type + Select the algorithm +to use for the Luma Spatial Filter (default +1D_HOR). Possible values: + + + + + + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF  + No filter + + + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR  + One-dimensional horizontal + + + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT  + One-dimensional vertical + + + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE  + Two-dimensional separable + + + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE  + Two-dimensional symmetrical +non-separable + + + + + + + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE  + enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type + Select the algorithm +for the Chroma Spatial Filter (default 1D_HOR). +Possible values are: + + + + + + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF  + No filter + + + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR  + One-dimensional horizontal + + + + + + + V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE  + enum v4l2_mpeg_cx2341x_video_temporal_filter_mode + Sets the Temporal +Filter mode (default MANUAL). Possible values +are: + + + + + + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL  + Choose the filter manually + + + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO  + Choose the filter automatically + + + + + + + V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER  + integer (0-31) + The setting for the +Temporal Filter. 0 = off, 31 = maximum. (Default is 8 for full-scale +capturing and 0 for scaled capturing.) + + + + V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE  + enum v4l2_mpeg_cx2341x_video_median_filter_type + Median Filter Type +(default OFF). Possible values are: + + + + + + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF  + No filter + + + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR  + Horizontal filter + + + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT  + Vertical filter + + + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT  + Horizontal and vertical filter + + + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG  + Diagonal filter + + + + + + + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM  + integer (0-255) + Threshold above which +the luminance median filter is enabled (default 0) + + + + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP  + integer (0-255) + Threshold below which +the luminance median filter is enabled (default 255) + + + + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM  + integer (0-255) + Threshold above which +the chroma median filter is enabled (default 0) + + + + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP  + integer (0-255) + Threshold below which +the chroma median filter is enabled (default 255) + + + + V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS  + boolean + + The CX2341X MPEG encoder +can insert one empty MPEG-2 PES packet into the stream between every +four video frames. The packet size is 2048 bytes, including the +packet_start_code_prefix and stream_id fields. The stream_id is 0xBF +(private stream 2). The payload consists of 0x00 bytes, to be filled +in by the application. 0 = do not insert, 1 = insert packets. + +
@@ -2092,6 +3072,289 @@ manually or automatically if set to zero. Unit, range and step are driver-specif For more details about RDS specification, refer to document, from CENELEC.
+ +
+ Flash Control Reference + + + Experimental + + This is an experimental +interface and may change in the future. + + + + The V4L2 flash controls are intended to provide generic access + to flash controller devices. Flash controller devices are + typically used in digital cameras. + + + + The interface can support both LED and xenon flash devices. As + of writing this, there is no xenon flash driver using this + interface. + + +
+ Supported use cases + +
+ Unsynchronised LED flash (software strobe) + + + Unsynchronised LED flash is controlled directly by the + host as the sensor. The flash must be enabled by the host + before the exposure of the image starts and disabled once + it ends. The host is fully responsible for the timing of + the flash. + + + Example of such device: Nokia N900. +
+ +
+ Synchronised LED flash (hardware strobe) + + + The synchronised LED flash is pre-programmed by the host + (power and timeout) but controlled by the sensor through a + strobe signal from the sensor to the flash. + + + + The sensor controls the flash duration and timing. This + information typically must be made available to the + sensor. + + +
+ +
+ LED flash as torch + + + LED flash may be used as torch in conjunction with another + use case involving camera or individually. + + +
+ +
+ + + Flash Control IDs + + + + + + + + + + + ID + Type + Description + + + + + + V4L2_CID_FLASH_CLASS + class + + + The FLASH class descriptor. + + + V4L2_CID_FLASH_LED_MODE + menu + + + Defines the mode of the flash LED, + the high-power white LED attached to the flash controller. + Setting this control may not be possible in presence of + some faults. See V4L2_CID_FLASH_FAULT. + + + + + + V4L2_FLASH_LED_MODE_NONE + Off. + + + V4L2_FLASH_LED_MODE_FLASH + Flash mode. + + + V4L2_FLASH_LED_MODE_TORCH + Torch mode. See V4L2_CID_FLASH_TORCH_INTENSITY. + + + + + + V4L2_CID_FLASH_STROBE_SOURCE + menu + + Defines the source of the flash LED + strobe. + + + + + + V4L2_FLASH_STROBE_SOURCE_SOFTWARE + The flash strobe is triggered by using + the V4L2_CID_FLASH_STROBE control. + + + V4L2_FLASH_STROBE_SOURCE_EXTERNAL + The flash strobe is triggered by an + external source. Typically this is a sensor, + which makes it possible to synchronises the + flash strobe start to exposure start. + + + + + + V4L2_CID_FLASH_STROBE + button + + + Strobe flash. Valid when + V4L2_CID_FLASH_LED_MODE is set to + V4L2_FLASH_LED_MODE_FLASH and V4L2_CID_FLASH_STROBE_SOURCE + is set to V4L2_FLASH_STROBE_SOURCE_SOFTWARE. Setting this + control may not be possible in presence of some faults. + See V4L2_CID_FLASH_FAULT. + + + V4L2_CID_FLASH_STROBE_STOP + button + + Stop flash strobe immediately. + + + V4L2_CID_FLASH_STROBE_STATUS + boolean + + + Strobe status: whether the flash + is strobing at the moment or not. This is a read-only + control. + + + V4L2_CID_FLASH_TIMEOUT + integer + + + Hardware timeout for flash. The + flash strobe is stopped after this period of time has + passed from the start of the strobe. + + + V4L2_CID_FLASH_INTENSITY + integer + + + Intensity of the flash strobe when + the flash LED is in flash mode + (V4L2_FLASH_LED_MODE_FLASH). The unit should be milliamps + (mA) if possible. + + + V4L2_CID_FLASH_TORCH_INTENSITY + integer + + + Intensity of the flash LED in + torch mode (V4L2_FLASH_LED_MODE_TORCH). The unit should be + milliamps (mA) if possible. Setting this control may not + be possible in presence of some faults. See + V4L2_CID_FLASH_FAULT. + + + V4L2_CID_FLASH_INDICATOR_INTENSITY + integer + + + Intensity of the indicator LED. + The indicator LED may be fully independent of the flash + LED. The unit should be microamps (uA) if possible. + + + V4L2_CID_FLASH_FAULT + bitmask + + + Faults related to the flash. The + faults tell about specific problems in the flash chip + itself or the LEDs attached to it. Faults may prevent + further use of some of the flash controls. In particular, + V4L2_CID_FLASH_LED_MODE is set to V4L2_FLASH_LED_MODE_NONE + if the fault affects the flash LED. Exactly which faults + have such an effect is chip dependent. Reading the faults + resets the control and returns the chip to a usable state + if possible. + + + + + + V4L2_FLASH_FAULT_OVER_VOLTAGE + Flash controller voltage to the flash LED + has exceeded the limit specific to the flash + controller. + + + V4L2_FLASH_FAULT_TIMEOUT + The flash strobe was still on when + the timeout set by the user --- + V4L2_CID_FLASH_TIMEOUT control --- has expired. + Not all flash controllers may set this in all + such conditions. + + + V4L2_FLASH_FAULT_OVER_TEMPERATURE + The flash controller has overheated. + + + V4L2_FLASH_FAULT_SHORT_CIRCUIT + The short circuit protection of the flash + controller has been triggered. + + + + + + V4L2_CID_FLASH_CHARGE + boolean + + Enable or disable charging of the xenon + flash capacitor. + + + V4L2_CID_FLASH_READY + boolean + + + Is the flash ready to strobe? + Xenon flashes require their capacitors charged before + strobing. LED flashes often require a cooldown period + after strobe during which another strobe will not be + possible. This is a read-only control. + + + + +
+ +
diff --git a/Documentation/DocBook/v4l/dev-osd.xml b/Documentation/DocBook/media/v4l/dev-osd.xml similarity index 100% rename from Documentation/DocBook/v4l/dev-osd.xml rename to Documentation/DocBook/media/v4l/dev-osd.xml diff --git a/Documentation/DocBook/v4l/dev-output.xml b/Documentation/DocBook/media/v4l/dev-output.xml similarity index 100% rename from Documentation/DocBook/v4l/dev-output.xml rename to Documentation/DocBook/media/v4l/dev-output.xml diff --git a/Documentation/DocBook/v4l/dev-overlay.xml b/Documentation/DocBook/media/v4l/dev-overlay.xml similarity index 100% rename from Documentation/DocBook/v4l/dev-overlay.xml rename to Documentation/DocBook/media/v4l/dev-overlay.xml diff --git a/Documentation/DocBook/v4l/dev-radio.xml b/Documentation/DocBook/media/v4l/dev-radio.xml similarity index 100% rename from Documentation/DocBook/v4l/dev-radio.xml rename to Documentation/DocBook/media/v4l/dev-radio.xml diff --git a/Documentation/DocBook/v4l/dev-raw-vbi.xml b/Documentation/DocBook/media/v4l/dev-raw-vbi.xml similarity index 100% rename from Documentation/DocBook/v4l/dev-raw-vbi.xml rename to Documentation/DocBook/media/v4l/dev-raw-vbi.xml diff --git a/Documentation/DocBook/v4l/dev-rds.xml b/Documentation/DocBook/media/v4l/dev-rds.xml similarity index 100% rename from Documentation/DocBook/v4l/dev-rds.xml rename to Documentation/DocBook/media/v4l/dev-rds.xml diff --git a/Documentation/DocBook/v4l/dev-sliced-vbi.xml b/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml similarity index 100% rename from Documentation/DocBook/v4l/dev-sliced-vbi.xml rename to Documentation/DocBook/media/v4l/dev-sliced-vbi.xml diff --git a/Documentation/DocBook/v4l/dev-subdev.xml b/Documentation/DocBook/media/v4l/dev-subdev.xml similarity index 100% rename from Documentation/DocBook/v4l/dev-subdev.xml rename to Documentation/DocBook/media/v4l/dev-subdev.xml diff --git a/Documentation/DocBook/v4l/dev-teletext.xml b/Documentation/DocBook/media/v4l/dev-teletext.xml similarity index 100% rename from Documentation/DocBook/v4l/dev-teletext.xml rename to Documentation/DocBook/media/v4l/dev-teletext.xml diff --git a/Documentation/DocBook/v4l/driver.xml b/Documentation/DocBook/media/v4l/driver.xml similarity index 100% rename from Documentation/DocBook/v4l/driver.xml rename to Documentation/DocBook/media/v4l/driver.xml diff --git a/Documentation/DocBook/v4l/fdl-appendix.xml b/Documentation/DocBook/media/v4l/fdl-appendix.xml similarity index 100% rename from Documentation/DocBook/v4l/fdl-appendix.xml rename to Documentation/DocBook/media/v4l/fdl-appendix.xml diff --git a/Documentation/DocBook/v4l/fieldseq_bt.pdf b/Documentation/DocBook/media/v4l/fieldseq_bt.pdf similarity index 100% rename from Documentation/DocBook/v4l/fieldseq_bt.pdf rename to Documentation/DocBook/media/v4l/fieldseq_bt.pdf diff --git a/Documentation/DocBook/v4l/fieldseq_tb.pdf b/Documentation/DocBook/media/v4l/fieldseq_tb.pdf similarity index 100% rename from Documentation/DocBook/v4l/fieldseq_tb.pdf rename to Documentation/DocBook/media/v4l/fieldseq_tb.pdf diff --git a/Documentation/DocBook/v4l/func-close.xml b/Documentation/DocBook/media/v4l/func-close.xml similarity index 100% rename from Documentation/DocBook/v4l/func-close.xml rename to Documentation/DocBook/media/v4l/func-close.xml diff --git a/Documentation/DocBook/media/v4l/func-ioctl.xml b/Documentation/DocBook/media/v4l/func-ioctl.xml new file mode 100644 index 0000000000000000000000000000000000000000..2de64be706f59fce8e1cabe42459b1bbbf196a60 --- /dev/null +++ b/Documentation/DocBook/media/v4l/func-ioctl.xml @@ -0,0 +1,79 @@ + + + V4L2 ioctl() + &manvol; + + + + v4l2-ioctl + Program a V4L2 device + + + + + #include <sys/ioctl.h> + + int ioctl + int fd + int request + void *argp + + + + + + Arguments + + + + fd + + &fd; + + + + request + + V4L2 ioctl request code as defined in the videodev2.h header file, for example +VIDIOC_QUERYCAP. + + + + argp + + Pointer to a function parameter, usually a structure. + + + + + + + Description + + The ioctl() function is used to program +V4L2 devices. The argument fd must be an open +file descriptor. An ioctl request has encoded +in it whether the argument is an input, output or read/write +parameter, and the size of the argument argp in +bytes. Macros and defines specifying V4L2 ioctl requests are located +in the videodev2.h header file. +Applications should use their own copy, not include the version in the +kernel sources on the system they compile on. All V4L2 ioctl requests, +their respective function and parameters are specified in . + + + + &return-value; + When an ioctl that takes an output or read/write parameter fails, + the parameter remains unmodified. + + + + diff --git a/Documentation/DocBook/v4l/func-mmap.xml b/Documentation/DocBook/media/v4l/func-mmap.xml similarity index 100% rename from Documentation/DocBook/v4l/func-mmap.xml rename to Documentation/DocBook/media/v4l/func-mmap.xml diff --git a/Documentation/DocBook/v4l/func-munmap.xml b/Documentation/DocBook/media/v4l/func-munmap.xml similarity index 100% rename from Documentation/DocBook/v4l/func-munmap.xml rename to Documentation/DocBook/media/v4l/func-munmap.xml diff --git a/Documentation/DocBook/v4l/func-open.xml b/Documentation/DocBook/media/v4l/func-open.xml similarity index 100% rename from Documentation/DocBook/v4l/func-open.xml rename to Documentation/DocBook/media/v4l/func-open.xml diff --git a/Documentation/DocBook/v4l/func-poll.xml b/Documentation/DocBook/media/v4l/func-poll.xml similarity index 100% rename from Documentation/DocBook/v4l/func-poll.xml rename to Documentation/DocBook/media/v4l/func-poll.xml diff --git a/Documentation/DocBook/v4l/func-read.xml b/Documentation/DocBook/media/v4l/func-read.xml similarity index 100% rename from Documentation/DocBook/v4l/func-read.xml rename to Documentation/DocBook/media/v4l/func-read.xml diff --git a/Documentation/DocBook/v4l/func-select.xml b/Documentation/DocBook/media/v4l/func-select.xml similarity index 100% rename from Documentation/DocBook/v4l/func-select.xml rename to Documentation/DocBook/media/v4l/func-select.xml diff --git a/Documentation/DocBook/v4l/func-write.xml b/Documentation/DocBook/media/v4l/func-write.xml similarity index 100% rename from Documentation/DocBook/v4l/func-write.xml rename to Documentation/DocBook/media/v4l/func-write.xml diff --git a/Documentation/DocBook/media/v4l/gen-errors.xml b/Documentation/DocBook/media/v4l/gen-errors.xml new file mode 100644 index 0000000000000000000000000000000000000000..5bbf3ce1973a8df5d72619ce3df4cc62de52b036 --- /dev/null +++ b/Documentation/DocBook/media/v4l/gen-errors.xml @@ -0,0 +1,78 @@ +Generic Error Codes + + + Generic error codes + + &cs-str; + + + + EBADF + The file descriptor is not a valid. + + + EBUSY + The ioctl can't be handled because the device is busy. This is + typically return while device is streaming, and an ioctl tried to + change something that would affect the stream, or would require the + usage of a hardware resource that was already allocated. The ioctl + must not be retried without performing another action to fix the + problem first (typically: stop the stream before retrying). + + + EFAULT + There was a failure while copying data from/to userspace, + probably caused by an invalid pointer reference. + + + EINVAL + One or more of the ioctl parameters are invalid or out of the + allowed range. This is a widely used error code. See the individual + ioctl requests for specific causes. + + + ENODEV + Device not found or was removed. + + + ENOMEM + There's not enough memory to handle the desired operation. + + + ENOTTY + The ioctl is not supported by the driver, actually meaning that + the required functionality is not available, or the file + descriptor is not for a media device. + + + ENOSPC + On USB devices, the stream ioctl's can return this error, meaning + that this request would overcommit the usb bandwidth reserved + for periodic transfers (up to 80% of the USB bandwidth). + + + ENOSYS or EOPNOTSUPP + Function not available for this device (dvb API only. Will likely + be replaced anytime soon by ENOTTY). + + + EPERM + Permission denied. Can be returned if the device needs write + permission, or some special capabilities is needed + (e. g. root) + + + EWOULDBLOCK + Operation would block. Used when the ioctl would need to wait + for an event, but the device was opened in non-blocking mode. + + + +
+ +Note 1: ioctls may return other error codes. Since errors may have side +effects such as a driver reset, applications should abort on unexpected errors. + + +Note 2: Request-specific error codes are listed in the individual +requests descriptions. diff --git a/Documentation/DocBook/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml similarity index 100% rename from Documentation/DocBook/v4l/io.xml rename to Documentation/DocBook/media/v4l/io.xml diff --git a/Documentation/DocBook/v4l/keytable.c.xml b/Documentation/DocBook/media/v4l/keytable.c.xml similarity index 100% rename from Documentation/DocBook/v4l/keytable.c.xml rename to Documentation/DocBook/media/v4l/keytable.c.xml diff --git a/Documentation/DocBook/v4l/libv4l.xml b/Documentation/DocBook/media/v4l/libv4l.xml similarity index 100% rename from Documentation/DocBook/v4l/libv4l.xml rename to Documentation/DocBook/media/v4l/libv4l.xml diff --git a/Documentation/DocBook/v4l/lirc_device_interface.xml b/Documentation/DocBook/media/v4l/lirc_device_interface.xml similarity index 99% rename from Documentation/DocBook/v4l/lirc_device_interface.xml rename to Documentation/DocBook/media/v4l/lirc_device_interface.xml index 0e0453f39e73d931166da65ed23ec613d54155b0..8d7eb6bf6312f4934c613912b7930d127c12956a 100644 --- a/Documentation/DocBook/v4l/lirc_device_interface.xml +++ b/Documentation/DocBook/media/v4l/lirc_device_interface.xml @@ -246,6 +246,8 @@ on working with the default settings initially. - +
+ &return-value; +
diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/media/v4l/media-controller.xml similarity index 100% rename from Documentation/DocBook/v4l/media-controller.xml rename to Documentation/DocBook/media/v4l/media-controller.xml diff --git a/Documentation/DocBook/v4l/media-func-close.xml b/Documentation/DocBook/media/v4l/media-func-close.xml similarity index 100% rename from Documentation/DocBook/v4l/media-func-close.xml rename to Documentation/DocBook/media/v4l/media-func-close.xml diff --git a/Documentation/DocBook/v4l/media-func-ioctl.xml b/Documentation/DocBook/media/v4l/media-func-ioctl.xml similarity index 59% rename from Documentation/DocBook/v4l/media-func-ioctl.xml rename to Documentation/DocBook/media/v4l/media-func-ioctl.xml index bda8604de15cd1bf9292a712b58eb5b257e5f1da..39478d0fbcaa68fd730d8edd5f647f9d64df5158 100644 --- a/Documentation/DocBook/v4l/media-func-ioctl.xml +++ b/Documentation/DocBook/media/v4l/media-func-ioctl.xml @@ -63,54 +63,11 @@ - Return Value + &return-value; - ioctl() returns 0 on - success. On failure, -1 is returned, and the - errno variable is set appropriately. Generic error codes - are listed below, and request-specific error codes are listed in the + Request-specific error codes are listed in the individual requests descriptions. When an ioctl that takes an output or read/write parameter fails, the parameter remains unmodified. - - - - EBADF - - fd is not a valid open file descriptor. - - - - - EFAULT - - argp references an inaccessible memory - area. - - - - EINVAL - - The request or the data pointed to by - argp is not valid. This is a very common error - code, see the individual ioctl requests listed in - for actual causes. - - - - ENOMEM - - Insufficient kernel memory was available to complete the - request. - - - - ENOTTY - - fd is not associated with a character - special device. - - - diff --git a/Documentation/DocBook/v4l/media-func-open.xml b/Documentation/DocBook/media/v4l/media-func-open.xml similarity index 100% rename from Documentation/DocBook/v4l/media-func-open.xml rename to Documentation/DocBook/media/v4l/media-func-open.xml diff --git a/Documentation/DocBook/v4l/media-ioc-device-info.xml b/Documentation/DocBook/media/v4l/media-ioc-device-info.xml similarity index 97% rename from Documentation/DocBook/v4l/media-ioc-device-info.xml rename to Documentation/DocBook/media/v4l/media-ioc-device-info.xml index 1f3237351bba6e306fbdb7332d65aa27ff6d2e3c..2ce521419e67ec5d8b503e6169e9859de6cf7da0 100644 --- a/Documentation/DocBook/v4l/media-ioc-device-info.xml +++ b/Documentation/DocBook/media/v4l/media-ioc-device-info.xml @@ -127,7 +127,6 @@ - Return value - This function doesn't return specific error codes. + &return-value; diff --git a/Documentation/DocBook/v4l/media-ioc-enum-entities.xml b/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml similarity index 100% rename from Documentation/DocBook/v4l/media-ioc-enum-entities.xml rename to Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml diff --git a/Documentation/DocBook/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml similarity index 98% rename from Documentation/DocBook/v4l/media-ioc-enum-links.xml rename to Documentation/DocBook/media/v4l/media-ioc-enum-links.xml index d2fc73ef8d5615cb75afe985abdf20be901d5d1e..355df43badc5d7dc34123f829bed0ef028c4539a 100644 --- a/Documentation/DocBook/v4l/media-ioc-enum-links.xml +++ b/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml @@ -139,7 +139,7 @@ - struct <structname>media_links_desc</structname> + struct <structname>media_link_desc</structname> &cs-str; diff --git a/Documentation/DocBook/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/media/v4l/media-ioc-setup-link.xml similarity index 87% rename from Documentation/DocBook/v4l/media-ioc-setup-link.xml rename to Documentation/DocBook/media/v4l/media-ioc-setup-link.xml index cec97af4dab47cb924966439fbe771dbcbdea12a..fc2e522ee65a98d2d8dbf012f05531323a5ccae5 100644 --- a/Documentation/DocBook/v4l/media-ioc-setup-link.xml +++ b/Documentation/DocBook/media/v4l/media-ioc-setup-link.xml @@ -71,15 +71,6 @@ &return-value; - - EBUSY - - The link properties can't be changed because the link is - currently busy. This can be caused, for instance, by an active media - stream (audio or video) on the link. The ioctl shouldn't be retried if - no other action is performed before to fix the problem. - - EINVAL diff --git a/Documentation/DocBook/v4l/pipeline.pdf b/Documentation/DocBook/media/v4l/pipeline.pdf similarity index 100% rename from Documentation/DocBook/v4l/pipeline.pdf rename to Documentation/DocBook/media/v4l/pipeline.pdf diff --git a/Documentation/DocBook/v4l/pixfmt-grey.xml b/Documentation/DocBook/media/v4l/pixfmt-grey.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-grey.xml rename to Documentation/DocBook/media/v4l/pixfmt-grey.xml diff --git a/Documentation/DocBook/v4l/pixfmt-m420.xml b/Documentation/DocBook/media/v4l/pixfmt-m420.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-m420.xml rename to Documentation/DocBook/media/v4l/pixfmt-m420.xml diff --git a/Documentation/DocBook/v4l/pixfmt-nv12.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-nv12.xml rename to Documentation/DocBook/media/v4l/pixfmt-nv12.xml diff --git a/Documentation/DocBook/v4l/pixfmt-nv12m.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-nv12m.xml rename to Documentation/DocBook/media/v4l/pixfmt-nv12m.xml diff --git a/Documentation/DocBook/v4l/pixfmt-nv12mt.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-nv12mt.xml rename to Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml diff --git a/Documentation/DocBook/v4l/pixfmt-nv16.xml b/Documentation/DocBook/media/v4l/pixfmt-nv16.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-nv16.xml rename to Documentation/DocBook/media/v4l/pixfmt-nv16.xml diff --git a/Documentation/DocBook/v4l/pixfmt-packed-rgb.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-packed-rgb.xml rename to Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml diff --git a/Documentation/DocBook/v4l/pixfmt-packed-yuv.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-yuv.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-packed-yuv.xml rename to Documentation/DocBook/media/v4l/pixfmt-packed-yuv.xml diff --git a/Documentation/DocBook/v4l/pixfmt-sbggr16.xml b/Documentation/DocBook/media/v4l/pixfmt-sbggr16.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-sbggr16.xml rename to Documentation/DocBook/media/v4l/pixfmt-sbggr16.xml diff --git a/Documentation/DocBook/v4l/pixfmt-sbggr8.xml b/Documentation/DocBook/media/v4l/pixfmt-sbggr8.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-sbggr8.xml rename to Documentation/DocBook/media/v4l/pixfmt-sbggr8.xml diff --git a/Documentation/DocBook/v4l/pixfmt-sgbrg8.xml b/Documentation/DocBook/media/v4l/pixfmt-sgbrg8.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-sgbrg8.xml rename to Documentation/DocBook/media/v4l/pixfmt-sgbrg8.xml diff --git a/Documentation/DocBook/v4l/pixfmt-sgrbg8.xml b/Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-sgrbg8.xml rename to Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml diff --git a/Documentation/DocBook/v4l/pixfmt-srggb10.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-srggb10.xml rename to Documentation/DocBook/media/v4l/pixfmt-srggb10.xml diff --git a/Documentation/DocBook/v4l/pixfmt-srggb12.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-srggb12.xml rename to Documentation/DocBook/media/v4l/pixfmt-srggb12.xml diff --git a/Documentation/DocBook/v4l/pixfmt-srggb8.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb8.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-srggb8.xml rename to Documentation/DocBook/media/v4l/pixfmt-srggb8.xml diff --git a/Documentation/DocBook/v4l/pixfmt-uyvy.xml b/Documentation/DocBook/media/v4l/pixfmt-uyvy.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-uyvy.xml rename to Documentation/DocBook/media/v4l/pixfmt-uyvy.xml diff --git a/Documentation/DocBook/v4l/pixfmt-vyuy.xml b/Documentation/DocBook/media/v4l/pixfmt-vyuy.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-vyuy.xml rename to Documentation/DocBook/media/v4l/pixfmt-vyuy.xml diff --git a/Documentation/DocBook/v4l/pixfmt-y10.xml b/Documentation/DocBook/media/v4l/pixfmt-y10.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-y10.xml rename to Documentation/DocBook/media/v4l/pixfmt-y10.xml diff --git a/Documentation/DocBook/v4l/pixfmt-y10b.xml b/Documentation/DocBook/media/v4l/pixfmt-y10b.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-y10b.xml rename to Documentation/DocBook/media/v4l/pixfmt-y10b.xml diff --git a/Documentation/DocBook/v4l/pixfmt-y12.xml b/Documentation/DocBook/media/v4l/pixfmt-y12.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-y12.xml rename to Documentation/DocBook/media/v4l/pixfmt-y12.xml diff --git a/Documentation/DocBook/v4l/pixfmt-y16.xml b/Documentation/DocBook/media/v4l/pixfmt-y16.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-y16.xml rename to Documentation/DocBook/media/v4l/pixfmt-y16.xml diff --git a/Documentation/DocBook/v4l/pixfmt-y41p.xml b/Documentation/DocBook/media/v4l/pixfmt-y41p.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-y41p.xml rename to Documentation/DocBook/media/v4l/pixfmt-y41p.xml diff --git a/Documentation/DocBook/v4l/pixfmt-yuv410.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv410.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-yuv410.xml rename to Documentation/DocBook/media/v4l/pixfmt-yuv410.xml diff --git a/Documentation/DocBook/v4l/pixfmt-yuv411p.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv411p.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-yuv411p.xml rename to Documentation/DocBook/media/v4l/pixfmt-yuv411p.xml diff --git a/Documentation/DocBook/v4l/pixfmt-yuv420.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv420.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-yuv420.xml rename to Documentation/DocBook/media/v4l/pixfmt-yuv420.xml diff --git a/Documentation/DocBook/v4l/pixfmt-yuv420m.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-yuv420m.xml rename to Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml diff --git a/Documentation/DocBook/v4l/pixfmt-yuv422p.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv422p.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-yuv422p.xml rename to Documentation/DocBook/media/v4l/pixfmt-yuv422p.xml diff --git a/Documentation/DocBook/v4l/pixfmt-yuyv.xml b/Documentation/DocBook/media/v4l/pixfmt-yuyv.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-yuyv.xml rename to Documentation/DocBook/media/v4l/pixfmt-yuyv.xml diff --git a/Documentation/DocBook/v4l/pixfmt-yvyu.xml b/Documentation/DocBook/media/v4l/pixfmt-yvyu.xml similarity index 100% rename from Documentation/DocBook/v4l/pixfmt-yvyu.xml rename to Documentation/DocBook/media/v4l/pixfmt-yvyu.xml diff --git a/Documentation/DocBook/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml similarity index 94% rename from Documentation/DocBook/v4l/pixfmt.xml rename to Documentation/DocBook/media/v4l/pixfmt.xml index deb660207f94700e04c1aa37106c8a567582b44d..2ff6b7776d7fe9f483ae4a00e713292fdb1d751d 100644 --- a/Documentation/DocBook/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -121,7 +121,7 @@ set this field to zero. an array of v4l2_plane_pix_format structures, describing all planes of that format. - struct <structname>vl42_plane_pix_format</structname> + struct <structname>v4l2_plane_pix_format</structname> &cs-str; @@ -741,10 +741,55 @@ information. V4L2_PIX_FMT_MPEG 'MPEG' - MPEG stream. The actual format is determined by + MPEG multiplexed stream. The actual format is determined by extended control V4L2_CID_MPEG_STREAM_TYPE, see . + + V4L2_PIX_FMT_H264 + 'H264' + H264 video elementary stream with start codes. + + + V4L2_PIX_FMT_H264_NO_SC + 'AVC1' + H264 video elementary stream without start codes. + + + V4L2_PIX_FMT_H263 + 'H263' + H263 video elementary stream. + + + V4L2_PIX_FMT_MPEG1 + 'MPG1' + MPEG1 video elementary stream. + + + V4L2_PIX_FMT_MPEG2 + 'MPG2' + MPEG2 video elementary stream. + + + V4L2_PIX_FMT_MPEG4 + 'MPG4' + MPEG4 video elementary stream. + + + V4L2_PIX_FMT_XVID + 'XVID' + Xvid video elementary stream. + + + V4L2_PIX_FMT_VC1_ANNEX_G + 'VC1G' + VC1, SMPTE 421M Annex G compliant stream. + + + V4L2_PIX_FMT_VC1_ANNEX_L + 'VC1L' + VC1, SMPTE 421M Annex L compliant stream. +
@@ -804,6 +849,12 @@ kernel sources in the file Documentation/video4linux/cx2341x/README.hm 'CPIA' YUV format used by the gspca cpia1 driver. + + V4L2_PIX_FMT_JPGL + 'JPGL' + JPEG-Light format (Pegasus Lossless JPEG) + used in Divio webcams NW 80x. + V4L2_PIX_FMT_SPCA501 'S501' @@ -854,6 +905,11 @@ kernel sources in the file Documentation/video4linux/cx2341x/README.hm 'PJPG' Pixart 73xx JPEG format used by the gspca driver. + + V4L2_PIX_FMT_SE401 + 'S401' + Compressed RGB format used by the gspca se401 driver + V4L2_PIX_FMT_SQ905C '905C' diff --git a/Documentation/DocBook/v4l/planar-apis.xml b/Documentation/DocBook/media/v4l/planar-apis.xml similarity index 100% rename from Documentation/DocBook/v4l/planar-apis.xml rename to Documentation/DocBook/media/v4l/planar-apis.xml diff --git a/Documentation/DocBook/v4l/remote_controllers.xml b/Documentation/DocBook/media/v4l/remote_controllers.xml similarity index 100% rename from Documentation/DocBook/v4l/remote_controllers.xml rename to Documentation/DocBook/media/v4l/remote_controllers.xml diff --git a/Documentation/DocBook/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml similarity index 99% rename from Documentation/DocBook/v4l/subdev-formats.xml rename to Documentation/DocBook/media/v4l/subdev-formats.xml index 8d3409d2c6320978186266c00518fc9e30dd888e..49c532ebbbbefe3a6aac004dd4192936ec14e880 100644 --- a/Documentation/DocBook/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -379,9 +379,6 @@
Bayer Patterns - - - @@ -2528,7 +2525,7 @@ Those data formats consist of an ordered sequence of 8-bit bytes obtained from JPEG compression process. Additionally to the - _JPEG prefix the format code is made of + _JPEG postfix the format code is made of the following information. The number of bus samples per entropy encoded byte. diff --git a/Documentation/DocBook/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml similarity index 97% rename from Documentation/DocBook/v4l/v4l2.xml rename to Documentation/DocBook/media/v4l/v4l2.xml index a7fd76d0dac1f6e04e8961e94fb29cc430bf2053..0d05e8747c12e24da9a2a4cebcdce4826e0858a4 100644 --- a/Documentation/DocBook/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -87,7 +87,7 @@ Remote Controller chapter. - Pawel + Pawel Osciak Designed and documented the multi-planar API. @@ -127,6 +127,15 @@ structs, ioctls) must be noted in more detail in the history chapter (compat.xml), along with the possible impact on existing drivers and applications. --> + + 3.1 + 2011-06-27 + mcc, po, hv + Documented that VIDIOC_QUERYCAP now returns a per-subsystem version instead of a per-driver one. + Standardize an error code for invalid ioctl. + Added V4L2_CTRL_TYPE_BITMASK. + + 2.6.39 2011-03-01 @@ -401,7 +410,7 @@ and discussions on the V4L mailing list. Video for Linux Two API Specification - Revision 2.6.39 + Revision 3.1 &sub-common; diff --git a/Documentation/DocBook/v4l/v4l2grab.c.xml b/Documentation/DocBook/media/v4l/v4l2grab.c.xml similarity index 100% rename from Documentation/DocBook/v4l/v4l2grab.c.xml rename to Documentation/DocBook/media/v4l/v4l2grab.c.xml diff --git a/Documentation/DocBook/v4l/vbi_525.pdf b/Documentation/DocBook/media/v4l/vbi_525.pdf similarity index 100% rename from Documentation/DocBook/v4l/vbi_525.pdf rename to Documentation/DocBook/media/v4l/vbi_525.pdf diff --git a/Documentation/DocBook/v4l/vbi_625.pdf b/Documentation/DocBook/media/v4l/vbi_625.pdf similarity index 100% rename from Documentation/DocBook/v4l/vbi_625.pdf rename to Documentation/DocBook/media/v4l/vbi_625.pdf diff --git a/Documentation/DocBook/v4l/vbi_hsync.pdf b/Documentation/DocBook/media/v4l/vbi_hsync.pdf similarity index 100% rename from Documentation/DocBook/v4l/vbi_hsync.pdf rename to Documentation/DocBook/media/v4l/vbi_hsync.pdf diff --git a/Documentation/DocBook/v4l/vidioc-cropcap.xml b/Documentation/DocBook/media/v4l/vidioc-cropcap.xml similarity index 95% rename from Documentation/DocBook/v4l/vidioc-cropcap.xml rename to Documentation/DocBook/media/v4l/vidioc-cropcap.xml index 816e90e283c541f104d16ccb92648482eb3695ae..b4f2f255211e37088052a8a78f44dd09dfd9dc46 100644 --- a/Documentation/DocBook/v4l/vidioc-cropcap.xml +++ b/Documentation/DocBook/media/v4l/vidioc-cropcap.xml @@ -156,19 +156,10 @@ on 22 Oct 2002 subject "Re:[V4L][patches!] Re:v4l2/kernel-2.5" --> EINVAL The &v4l2-cropcap; type is -invalid or the ioctl is not supported. This is not permitted for -video capture, output and overlay devices, which must support -VIDIOC_CROPCAP. +invalid. This is not permitted for video capture, output and overlay devices, +which must support VIDIOC_CROPCAP. - - diff --git a/Documentation/DocBook/v4l/vidioc-dbg-g-chip-ident.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml similarity index 97% rename from Documentation/DocBook/v4l/vidioc-dbg-g-chip-ident.xml rename to Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml index 4a09e203af0f5c806a383473f07e8853729635f2..4ecd966808de77a1c66e999322bf420fc8910021 100644 --- a/Documentation/DocBook/v4l/vidioc-dbg-g-chip-ident.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml @@ -258,18 +258,9 @@ could not identify it. EINVAL - The driver does not support this ioctl, or the -match_type is invalid. + The match_type is invalid. - - diff --git a/Documentation/DocBook/v4l/vidioc-dbg-g-register.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml similarity index 94% rename from Documentation/DocBook/v4l/vidioc-dbg-g-register.xml rename to Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml index 980c7f3e2fd6779c22d7d539de0b2a7abc251dec..a44aebc7997ae1ecfa95885d53b62973ce6ae75b 100644 --- a/Documentation/DocBook/v4l/vidioc-dbg-g-register.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml @@ -246,15 +246,6 @@ register. &return-value; - - EINVAL - - The driver does not support this ioctl, or the kernel -was not compiled with the CONFIG_VIDEO_ADV_DEBUG -option, or the match_type is invalid, or the -selected chip or register does not exist. - - EPERM @@ -265,11 +256,3 @@ to execute these ioctls. - - diff --git a/Documentation/DocBook/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml similarity index 84% rename from Documentation/DocBook/v4l/vidioc-dqevent.xml rename to Documentation/DocBook/media/v4l/vidioc-dqevent.xml index 4e0a7cc30812d9cc5254ad8c24ba9ed4f5e6338a..7769642ee431b11a83d423d260ea8ed1e87e66aa 100644 --- a/Documentation/DocBook/v4l/vidioc-dqevent.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml @@ -79,6 +79,13 @@ Event data for event V4L2_EVENT_VSYNC. + + + &v4l2-event-ctrl; + ctrl + Event data for event V4L2_EVENT_CTRL. + + __u8 @@ -109,9 +116,17 @@ Event timestamp. + + u32 + id + + The ID associated with the event source. If the event does not + have an associated ID (this depends on the event type), then this + is 0. + __u32 - reserved[9] + reserved[8] Reserved for future extensions. Drivers must set the array to zero. @@ -121,11 +136,7 @@ + + &return-value; + - diff --git a/Documentation/DocBook/v4l/vidioc-encoder-cmd.xml b/Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml similarity index 96% rename from Documentation/DocBook/v4l/vidioc-encoder-cmd.xml rename to Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml index b0dde943825c084187cd1e575294efd218734e23..af7f3f2a36dd2c241bb8d971f4ecab2f3735eb2e 100644 --- a/Documentation/DocBook/v4l/vidioc-encoder-cmd.xml +++ b/Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml @@ -180,8 +180,7 @@ Pictures, rather than immediately. EINVAL - The driver does not support this ioctl, or the -cmd field is invalid. + The cmd field is invalid. @@ -194,11 +193,3 @@ the encoder was not running. - - diff --git a/Documentation/DocBook/v4l/vidioc-enum-dv-presets.xml b/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml similarity index 100% rename from Documentation/DocBook/v4l/vidioc-enum-dv-presets.xml rename to Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml diff --git a/Documentation/DocBook/v4l/vidioc-enum-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml similarity index 100% rename from Documentation/DocBook/v4l/vidioc-enum-fmt.xml rename to Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml diff --git a/Documentation/DocBook/v4l/vidioc-enum-frameintervals.xml b/Documentation/DocBook/media/v4l/vidioc-enum-frameintervals.xml similarity index 97% rename from Documentation/DocBook/v4l/vidioc-enum-frameintervals.xml rename to Documentation/DocBook/media/v4l/vidioc-enum-frameintervals.xml index 3c216e113a546fe74c9604382a3937665765a5bc..5fd72c4c33e352ba3edded10ee5ad27fc87f6d86 100644 --- a/Documentation/DocBook/v4l/vidioc-enum-frameintervals.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enum-frameintervals.xml @@ -254,17 +254,6 @@ enumerated. &return-value; - - See the description section above for a list of return -values that errno can have. - - diff --git a/Documentation/DocBook/v4l/vidioc-enum-framesizes.xml b/Documentation/DocBook/media/v4l/vidioc-enum-framesizes.xml similarity index 97% rename from Documentation/DocBook/v4l/vidioc-enum-framesizes.xml rename to Documentation/DocBook/media/v4l/vidioc-enum-framesizes.xml index 6afa4542c818707080989ea0998d02d700bf4479..f77a13f486d7968e60128d31a485bde9e580bc5f 100644 --- a/Documentation/DocBook/v4l/vidioc-enum-framesizes.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enum-framesizes.xml @@ -267,16 +267,5 @@ application should zero out all members except for the &return-value; - - See the description section above for a list of return -values that errno can have. - - diff --git a/Documentation/DocBook/v4l/vidioc-enumaudio.xml b/Documentation/DocBook/media/v4l/vidioc-enumaudio.xml similarity index 89% rename from Documentation/DocBook/v4l/vidioc-enumaudio.xml rename to Documentation/DocBook/media/v4l/vidioc-enumaudio.xml index 9ae8f2d3a96f3e06cd56260cf975ab5feab9a6ea..ea816ab2e49e643106dd9307d6688e2358118ef7 100644 --- a/Documentation/DocBook/v4l/vidioc-enumaudio.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enumaudio.xml @@ -68,19 +68,9 @@ until the driver returns EINVAL. EINVAL - The number of the audio input is out of bounds, or -there are no audio inputs at all and this ioctl is not -supported. + The number of the audio input is out of bounds. - - diff --git a/Documentation/DocBook/v4l/vidioc-enumaudioout.xml b/Documentation/DocBook/media/v4l/vidioc-enumaudioout.xml similarity index 90% rename from Documentation/DocBook/v4l/vidioc-enumaudioout.xml rename to Documentation/DocBook/media/v4l/vidioc-enumaudioout.xml index d3d7c0ab17b86fd4f06936cde81a644df86f9e91..2e87cedb0d32f00a146e97d7ca449e3972e4c248 100644 --- a/Documentation/DocBook/v4l/vidioc-enumaudioout.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enumaudioout.xml @@ -71,19 +71,9 @@ signal to a sound card are not audio outputs in this sense. EINVAL - The number of the audio output is out of bounds, or -there are no audio outputs at all and this ioctl is not -supported. + The number of the audio output is out of bounds. - - diff --git a/Documentation/DocBook/v4l/vidioc-enuminput.xml b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml similarity index 100% rename from Documentation/DocBook/v4l/vidioc-enuminput.xml rename to Documentation/DocBook/media/v4l/vidioc-enuminput.xml diff --git a/Documentation/DocBook/v4l/vidioc-enumoutput.xml b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml similarity index 100% rename from Documentation/DocBook/v4l/vidioc-enumoutput.xml rename to Documentation/DocBook/media/v4l/vidioc-enumoutput.xml diff --git a/Documentation/DocBook/v4l/vidioc-enumstd.xml b/Documentation/DocBook/media/v4l/vidioc-enumstd.xml similarity index 100% rename from Documentation/DocBook/v4l/vidioc-enumstd.xml rename to Documentation/DocBook/media/v4l/vidioc-enumstd.xml diff --git a/Documentation/DocBook/v4l/vidioc-g-audio.xml b/Documentation/DocBook/media/v4l/vidioc-g-audio.xml similarity index 93% rename from Documentation/DocBook/v4l/vidioc-g-audio.xml rename to Documentation/DocBook/media/v4l/vidioc-g-audio.xml index 65361a8c2b05098df74f4ed3a479dc274cf096a0..d7bb9b3738f653db6aac1f84a09aaf190f47b9e5 100644 --- a/Documentation/DocBook/v4l/vidioc-g-audio.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-audio.xml @@ -164,25 +164,9 @@ tuner. No audio inputs combine with the current video input, or the number of the selected audio input is out of bounds or it does -not combine, or there are no audio inputs at all and the ioctl is not -supported. - - - - EBUSY - - I/O is in progress, the input cannot be -switched. +not combine. - - diff --git a/Documentation/DocBook/v4l/vidioc-g-audioout.xml b/Documentation/DocBook/media/v4l/vidioc-g-audioout.xml similarity index 92% rename from Documentation/DocBook/v4l/vidioc-g-audioout.xml rename to Documentation/DocBook/media/v4l/vidioc-g-audioout.xml index 3632730c5c6e86ab3aba5ce41a2df9b71a73e29c..200a2704a970842f68839a0afb2ffd7807b5897f 100644 --- a/Documentation/DocBook/v4l/vidioc-g-audioout.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-audioout.xml @@ -130,25 +130,9 @@ applications must set the array to zero. No audio outputs combine with the current video output, or the number of the selected audio output is out of bounds or -it does not combine, or there are no audio outputs at all and the -ioctl is not supported. - - - - EBUSY - - I/O is in progress, the output cannot be -switched. +it does not combine. - - diff --git a/Documentation/DocBook/v4l/vidioc-g-crop.xml b/Documentation/DocBook/media/v4l/vidioc-g-crop.xml similarity index 93% rename from Documentation/DocBook/v4l/vidioc-g-crop.xml rename to Documentation/DocBook/media/v4l/vidioc-g-crop.xml index d235b1dedbedb465b85551873423093280399d7c..01a50640dce0b072c7f67f58b9d0f17aa00c50fc 100644 --- a/Documentation/DocBook/v4l/vidioc-g-crop.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-crop.xml @@ -122,22 +122,5 @@ for &v4l2-cropcap; bounds is used. &return-value; - - - - EINVAL - - Cropping is not supported. - - - - - diff --git a/Documentation/DocBook/v4l/vidioc-g-ctrl.xml b/Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml similarity index 94% rename from Documentation/DocBook/v4l/vidioc-g-ctrl.xml rename to Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml index 8b5e6ff7f3df7a6340c6f01486ba9de3b731fc2f..5146d00782e339468763cc853849ee12879bafb2 100644 --- a/Documentation/DocBook/v4l/vidioc-g-ctrl.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml @@ -117,6 +117,13 @@ because another applications took over control of the device function this control belongs to. + + EACCES + + Attempt to set a read-only control or to get a + write-only control. + + diff --git a/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml b/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml similarity index 96% rename from Documentation/DocBook/v4l/vidioc-g-dv-preset.xml rename to Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml index d733721a7519e460b7df5fe831e8611858a6a098..7940c114939310a7210216a35382743227aebe7d 100644 --- a/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml @@ -97,14 +97,8 @@ If the preset is not supported, it returns an &EINVAL; - + + + &return-value; - - diff --git a/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml similarity index 98% rename from Documentation/DocBook/v4l/vidioc-g-dv-timings.xml rename to Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml index d5ec6abf0ce2b52c7125cb0aea20afeca23eaf3c..4a8648ae9a63ad373e6a1ab8ccdbbf843963a78f 100644 --- a/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml @@ -212,12 +212,7 @@ bit 0 (V4L2_DV_VSYNC_POS_POL) is for vertical sync polarity and bit 1 (V4L2_DV_H + + &return-value; + - - diff --git a/Documentation/DocBook/v4l/vidioc-g-enc-index.xml b/Documentation/DocBook/media/v4l/vidioc-g-enc-index.xml similarity index 95% rename from Documentation/DocBook/v4l/vidioc-g-enc-index.xml rename to Documentation/DocBook/media/v4l/vidioc-g-enc-index.xml index 9f242e4b2948991f4449fc3d5eddf5c0024bbdd7..2aef02c9044e039db683f9b37307e24ae0c8eb3e 100644 --- a/Documentation/DocBook/v4l/vidioc-g-enc-index.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-enc-index.xml @@ -192,22 +192,5 @@ this mask to obtain the picture coding type. &return-value; - - - - EINVAL - - The driver does not support this ioctl. - - - - - diff --git a/Documentation/DocBook/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml similarity index 95% rename from Documentation/DocBook/v4l/vidioc-g-ext-ctrls.xml rename to Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml index 3aa7f8f9ff0ca1f421253bb100cbda09df13858c..5122ce87e0b806a490175bec8600662b7f2a0cd5 100644 --- a/Documentation/DocBook/v4l/vidioc-g-ext-ctrls.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml @@ -250,6 +250,13 @@ These controls are described in . + + V4L2_CTRL_CLASS_FLASH + 0x9c0000 + The class containing flash device controls. +These controls are described in . + @@ -294,6 +301,13 @@ The field size is set to a value that is enough to store the payload and this error code is returned. + + EACCES + + Attempt to try or set a read-only control or to get a + write-only control. + + diff --git a/Documentation/DocBook/v4l/vidioc-g-fbuf.xml b/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml similarity index 97% rename from Documentation/DocBook/v4l/vidioc-g-fbuf.xml rename to Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml index e7dda4822f04873ed9eca7477d357fc8df3aa7f2..055718231bc18ce81ddb9287d5633a5ab412388c 100644 --- a/Documentation/DocBook/v4l/vidioc-g-fbuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml @@ -445,29 +445,12 @@ by a privileged user to negotiate the parameters for a destructive overlay. - - EBUSY - - The framebuffer parameters cannot be changed at this -time because overlay is already enabled, or capturing is enabled -and the hardware cannot capture and overlay simultaneously. - - EINVAL - The ioctl is not supported or the -VIDIOC_S_FBUF parameters are unsuitable. + The VIDIOC_S_FBUF parameters are unsuitable. - - diff --git a/Documentation/DocBook/v4l/vidioc-g-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml similarity index 93% rename from Documentation/DocBook/v4l/vidioc-g-fmt.xml rename to Documentation/DocBook/media/v4l/vidioc-g-fmt.xml index a4ae59b664ebaa12c9b8ae6999cce8525f9a8788..17fbda15137b64f2933ab2f65e6d7a65c9046a1e 100644 --- a/Documentation/DocBook/v4l/vidioc-g-fmt.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml @@ -183,30 +183,14 @@ capture and output devices. &return-value; - - EBUSY - - The data format cannot be changed at this -time, for example because I/O is already in progress. - - EINVAL The &v4l2-format; type -field is invalid, the requested buffer type not supported, or -VIDIOC_TRY_FMT was called and is not -supported with this buffer type. +field is invalid, the requested buffer type not supported, or the +format is not supported with this buffer type. - - diff --git a/Documentation/DocBook/v4l/vidioc-g-frequency.xml b/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml similarity index 100% rename from Documentation/DocBook/v4l/vidioc-g-frequency.xml rename to Documentation/DocBook/media/v4l/vidioc-g-frequency.xml diff --git a/Documentation/DocBook/v4l/vidioc-g-input.xml b/Documentation/DocBook/media/v4l/vidioc-g-input.xml similarity index 85% rename from Documentation/DocBook/v4l/vidioc-g-input.xml rename to Documentation/DocBook/media/v4l/vidioc-g-input.xml index ed076e92760dfbe7aff4cd1a3572785cf334663b..08ae82f131f2b952df2a0f5488b49d0747776153 100644 --- a/Documentation/DocBook/v4l/vidioc-g-input.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-input.xml @@ -75,26 +75,9 @@ querying or negotiating any other parameters. EINVAL - The number of the video input is out of bounds, or -there are no video inputs at all and this ioctl is not -supported. - - - - EBUSY - - I/O is in progress, the input cannot be -switched. + The number of the video input is out of bounds. - - diff --git a/Documentation/DocBook/v4l/vidioc-g-jpegcomp.xml b/Documentation/DocBook/media/v4l/vidioc-g-jpegcomp.xml similarity index 93% rename from Documentation/DocBook/v4l/vidioc-g-jpegcomp.xml rename to Documentation/DocBook/media/v4l/vidioc-g-jpegcomp.xml index 77394b28741149569a6446e2507daa52948fbcb4..01ea24b84385c8b83765fa28ca7a6f78d76f680d 100644 --- a/Documentation/DocBook/v4l/vidioc-g-jpegcomp.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-jpegcomp.xml @@ -159,22 +159,5 @@ to add them. &return-value; - - - - EINVAL - - This ioctl is not supported. - - - - - diff --git a/Documentation/DocBook/v4l/vidioc-g-modulator.xml b/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml similarity index 100% rename from Documentation/DocBook/v4l/vidioc-g-modulator.xml rename to Documentation/DocBook/media/v4l/vidioc-g-modulator.xml diff --git a/Documentation/DocBook/v4l/vidioc-g-output.xml b/Documentation/DocBook/media/v4l/vidioc-g-output.xml similarity index 87% rename from Documentation/DocBook/v4l/vidioc-g-output.xml rename to Documentation/DocBook/media/v4l/vidioc-g-output.xml index 3ea8c0ed812ef046956a33a9956ba3305ac4bd0f..fd45f1c13ccf445b89e582036b40c3a7a94ab86c 100644 --- a/Documentation/DocBook/v4l/vidioc-g-output.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-output.xml @@ -76,25 +76,9 @@ negotiating any other parameters. EINVAL The number of the video output is out of bounds, or -there are no video outputs at all and this ioctl is not -supported. - - - - EBUSY - - I/O is in progress, the output cannot be -switched. +there are no video outputs at all. - - diff --git a/Documentation/DocBook/v4l/vidioc-g-parm.xml b/Documentation/DocBook/media/v4l/vidioc-g-parm.xml similarity index 97% rename from Documentation/DocBook/v4l/vidioc-g-parm.xml rename to Documentation/DocBook/media/v4l/vidioc-g-parm.xml index 392aa9e5571ec80f2e5ec465a5ccff9acffdcb45..19b1d85dd668ce31b50a975dcf2d20cb665edecb 100644 --- a/Documentation/DocBook/v4l/vidioc-g-parm.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-parm.xml @@ -311,22 +311,5 @@ excessive motion blur. &return-value; - - - - EINVAL - - This ioctl is not supported. - - - - - diff --git a/Documentation/DocBook/v4l/vidioc-g-priority.xml b/Documentation/DocBook/media/v4l/vidioc-g-priority.xml similarity index 97% rename from Documentation/DocBook/v4l/vidioc-g-priority.xml rename to Documentation/DocBook/media/v4l/vidioc-g-priority.xml index 5fb001978645a337560b26d5f4b8aded252e5bd5..8f5e3da7002fee8a68279dd1ee4a30939d6776e3 100644 --- a/Documentation/DocBook/v4l/vidioc-g-priority.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-priority.xml @@ -120,8 +120,7 @@ recording. EINVAL - The requested priority value is invalid, or the -driver does not support access priorities. + The requested priority value is invalid. diff --git a/Documentation/DocBook/v4l/vidioc-g-sliced-vbi-cap.xml b/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml similarity index 97% rename from Documentation/DocBook/v4l/vidioc-g-sliced-vbi-cap.xml rename to Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml index 10e721b17374d6bbd718b3b8f21f4dbe8f838dc6..71741daaf7252a8d612ce744072b528e5b7a156b 100644 --- a/Documentation/DocBook/v4l/vidioc-g-sliced-vbi-cap.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml @@ -246,19 +246,10 @@ line systems. EINVAL - The device does not support sliced VBI capturing or -output, or the value in the type field is + The value in the type field is wrong. - - diff --git a/Documentation/DocBook/v4l/vidioc-g-std.xml b/Documentation/DocBook/media/v4l/vidioc-g-std.xml similarity index 90% rename from Documentation/DocBook/v4l/vidioc-g-std.xml rename to Documentation/DocBook/media/v4l/vidioc-g-std.xml index 912f8513e5daeb5ef0fe2a91876ae49af19f5a79..37996f25b5d406bd237048c5bb77589d68dc1413 100644 --- a/Documentation/DocBook/v4l/vidioc-g-std.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-std.xml @@ -82,14 +82,7 @@ standards. EINVAL - This ioctl is not supported, or the -VIDIOC_S_STD parameter was unsuitable. - - - - EBUSY - - The device is busy and therefore can not change the standard + The VIDIOC_S_STD parameter was unsuitable. diff --git a/Documentation/DocBook/v4l/vidioc-g-tuner.xml b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml similarity index 100% rename from Documentation/DocBook/v4l/vidioc-g-tuner.xml rename to Documentation/DocBook/media/v4l/vidioc-g-tuner.xml diff --git a/Documentation/DocBook/v4l/vidioc-log-status.xml b/Documentation/DocBook/media/v4l/vidioc-log-status.xml similarity index 80% rename from Documentation/DocBook/v4l/vidioc-log-status.xml rename to Documentation/DocBook/media/v4l/vidioc-log-status.xml index 2634b7c88b580d7c14c94435ac21811b3ebc064c..5ded7d35e27b5b02a247b14ca068ababf2533f1b 100644 --- a/Documentation/DocBook/v4l/vidioc-log-status.xml +++ b/Documentation/DocBook/media/v4l/vidioc-log-status.xml @@ -37,22 +37,5 @@ was introduced in Linux 2.6.15. &return-value; - - - - EINVAL - - The driver does not support this ioctl. - - - - - diff --git a/Documentation/DocBook/v4l/vidioc-overlay.xml b/Documentation/DocBook/media/v4l/vidioc-overlay.xml similarity index 90% rename from Documentation/DocBook/v4l/vidioc-overlay.xml rename to Documentation/DocBook/media/v4l/vidioc-overlay.xml index 1036c582cc15b92e98e161ed98b3abb635f40ea3..250a7de1877f424919235ea27cf4c90253c9da52 100644 --- a/Documentation/DocBook/v4l/vidioc-overlay.xml +++ b/Documentation/DocBook/media/v4l/vidioc-overlay.xml @@ -65,19 +65,10 @@ EINVAL - Video overlay is not supported, or the -parameters have not been set up. See The overlay parameters have not been set up. See for the necessary steps. - - diff --git a/Documentation/DocBook/v4l/vidioc-qbuf.xml b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml similarity index 95% rename from Documentation/DocBook/v4l/vidioc-qbuf.xml rename to Documentation/DocBook/media/v4l/vidioc-qbuf.xml index f2b11f8a40310eebbe48d0839f7f0125c92bb201..9caa49af580fe2a2ae5607a30f1a5d2141ff072a 100644 --- a/Documentation/DocBook/v4l/vidioc-qbuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml @@ -158,15 +158,6 @@ or no buffers have been allocated yet, or the userptr or length are invalid. - - - ENOMEM - - Not enough physical or virtual memory was available to -enqueue a user pointer buffer. - - - EIO VIDIOC_DQBUF failed due to an @@ -184,11 +175,3 @@ continue streaming. - - diff --git a/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml b/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml similarity index 79% rename from Documentation/DocBook/v4l/vidioc-query-dv-preset.xml rename to Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml index d272f7ab91b83c2cd19e916c5a56e65480791335..23b17f60421144900e5cc5daabb3d036cecb11df 100644 --- a/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml +++ b/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml @@ -61,27 +61,5 @@ returned. &return-value; - - - EINVAL - - This ioctl is not supported. - - - - EBUSY - - The device is busy and therefore can not sense the preset - - - - - diff --git a/Documentation/DocBook/v4l/vidioc-querybuf.xml b/Documentation/DocBook/media/v4l/vidioc-querybuf.xml similarity index 100% rename from Documentation/DocBook/v4l/vidioc-querybuf.xml rename to Documentation/DocBook/media/v4l/vidioc-querybuf.xml diff --git a/Documentation/DocBook/v4l/vidioc-querycap.xml b/Documentation/DocBook/media/v4l/vidioc-querycap.xml similarity index 93% rename from Documentation/DocBook/v4l/vidioc-querycap.xml rename to Documentation/DocBook/media/v4l/vidioc-querycap.xml index f29f1b86213c68b55744420f8cb65eeaff708806..e3664d6f2de4feff72075b547235f6ad1aef303b 100644 --- a/Documentation/DocBook/v4l/vidioc-querycap.xml +++ b/Documentation/DocBook/media/v4l/vidioc-querycap.xml @@ -67,9 +67,8 @@ driver is not compatible with this specification the ioctl returns an Name of the driver, a unique NUL-terminated ASCII string. For example: "bttv". Driver specific applications can use this information to verify the driver identity. It is also useful -to work around known bugs, or to identify drivers in error reports. -The driver version is stored in the version -field.Storing strings in fixed sized arrays is bad +to work around known bugs, or to identify drivers in error reports. +Storing strings in fixed sized arrays is bad practice but unavoidable here. Drivers and applications should take precautions to never read or write beyond the end of the array and to make sure the strings are properly NUL-terminated. @@ -100,9 +99,13 @@ empty string (bus_info[0] = 0). - diff --git a/Documentation/DocBook/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml similarity index 97% rename from Documentation/DocBook/v4l/vidioc-queryctrl.xml rename to Documentation/DocBook/media/v4l/vidioc-queryctrl.xml index 0d5e8283cf32f9d8155d236430150ca5b6ea0380..677ea646c29fc71c6d8b9970cbb230d1784a46d1 100644 --- a/Documentation/DocBook/v4l/vidioc-queryctrl.xml +++ b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml @@ -156,7 +156,8 @@ signed value. Maximum value, inclusive. This field gives an upper bound for V4L2_CTRL_TYPE_INTEGER controls and the highest valid index for V4L2_CTRL_TYPE_MENU -controls. +controls. For V4L2_CTRL_TYPE_BITMASK controls it is the +set of usable bits. For V4L2_CTRL_TYPE_STRING controls the maximum value gives the maximum length of the string. This length does not include the terminating zero. It may not be valid for any other type of control, including @@ -289,6 +290,15 @@ values which are actually different on the hardware. The control has a menu of N choices. The names of the menu items can be enumerated with the VIDIOC_QUERYMENU ioctl. + + + V4L2_CTRL_TYPE_BITMASK + 0 + n/a + any + A bitmask field. The maximum value is the set of bits that can +be used, all other bits are to be 0. The maximum value is interpreted as a __u32, +allowing the use of bit 31 in the bitmask. V4L2_CTRL_TYPE_BUTTON diff --git a/Documentation/DocBook/v4l/vidioc-querystd.xml b/Documentation/DocBook/media/v4l/vidioc-querystd.xml similarity index 78% rename from Documentation/DocBook/v4l/vidioc-querystd.xml rename to Documentation/DocBook/media/v4l/vidioc-querystd.xml index 1a9e60393091e0519ecd1a53848b2d1ad872b359..4b79c7c04ed6631c30adc168cf18d5e6608d8478 100644 --- a/Documentation/DocBook/v4l/vidioc-querystd.xml +++ b/Documentation/DocBook/media/v4l/vidioc-querystd.xml @@ -62,28 +62,5 @@ current video input or output. &return-value; - - - - EINVAL - - This ioctl is not supported. - - - - EBUSY - - The device is busy and therefore can not detect the standard - - - - - diff --git a/Documentation/DocBook/v4l/vidioc-reqbufs.xml b/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml similarity index 92% rename from Documentation/DocBook/v4l/vidioc-reqbufs.xml rename to Documentation/DocBook/media/v4l/vidioc-reqbufs.xml index 69800ae233483484fb13076988ffe202d08de717..7be4b1d29b909a3383a901d9dabbb44fa5697d22 100644 --- a/Documentation/DocBook/v4l/vidioc-reqbufs.xml +++ b/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml @@ -121,14 +121,6 @@ higher. This array should be zeroed by applications. &return-value; - - EBUSY - - The driver supports multiple opens and I/O is already -in progress, or reallocation of buffers was attempted although one or -more are still mapped. - - EINVAL @@ -140,11 +132,3 @@ supported. - - diff --git a/Documentation/DocBook/v4l/vidioc-s-hw-freq-seek.xml b/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml similarity index 100% rename from Documentation/DocBook/v4l/vidioc-s-hw-freq-seek.xml rename to Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml diff --git a/Documentation/DocBook/v4l/vidioc-streamon.xml b/Documentation/DocBook/media/v4l/vidioc-streamon.xml similarity index 92% rename from Documentation/DocBook/v4l/vidioc-streamon.xml rename to Documentation/DocBook/media/v4l/vidioc-streamon.xml index 75ed39bf4d2bb4b8c64909b52d7348f2930cef3e..81cca4569050da8d789dc68973798b69fdbc8a35 100644 --- a/Documentation/DocBook/v4l/vidioc-streamon.xml +++ b/Documentation/DocBook/media/v4l/vidioc-streamon.xml @@ -88,9 +88,9 @@ synchronize with other events. EINVAL - Streaming I/O is not supported, the buffer -type is not supported, or no buffers have -been allocated (memory mapping) or enqueued (output) yet. + The buffertype is not supported, + or no buffers have been allocated (memory mapping) or enqueued + (output) yet. @@ -105,11 +105,3 @@ been allocated (memory mapping) or enqueued (output) yet. - - diff --git a/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml similarity index 100% rename from Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml rename to Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml diff --git a/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml similarity index 100% rename from Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml rename to Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml diff --git a/Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml similarity index 100% rename from Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml rename to Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml diff --git a/Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml similarity index 100% rename from Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml rename to Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml diff --git a/Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml similarity index 99% rename from Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml rename to Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml index f367c570c530e20acc7fa29782b3a12fe9c3f13e..a67cde6f8c54493f0f7e1b367411d0a8bf220c53 100644 --- a/Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml @@ -177,4 +177,7 @@ + + &return-value; + diff --git a/Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-frame-interval.xml similarity index 100% rename from Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml rename to Documentation/DocBook/media/v4l/vidioc-subdev-g-frame-interval.xml diff --git a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml new file mode 100644 index 0000000000000000000000000000000000000000..69c0d8a2a3d2dd812847a30d59969209d8917127 --- /dev/null +++ b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml @@ -0,0 +1,297 @@ + + + ioctl VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT + &manvol; + + + + VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT + Subscribe or unsubscribe event + + + + + + int ioctl + int fd + int request + struct v4l2_event_subscription +*argp + + + + + + Arguments + + + + fd + + &fd; + + + + request + + VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT + + + + argp + + + + + + + + + Description + + Subscribe or unsubscribe V4L2 event. Subscribed events are + dequeued by using the &VIDIOC-DQEVENT; ioctl. + + + struct <structname>v4l2_event_subscription</structname> + + &cs-str; + + + __u32 + type + Type of the event. + + + __u32 + id + ID of the event source. If there is no ID associated with + the event source, then set this to 0. Whether or not an event + needs an ID depends on the event type. + + + __u32 + flags + Event flags, see . + + + __u32 + reserved[5] + Reserved for future extensions. Drivers and applications + must set the array to zero. + + + +
+ + + Event Types + + &cs-def; + + + V4L2_EVENT_ALL + 0 + All events. V4L2_EVENT_ALL is valid only for + VIDIOC_UNSUBSCRIBE_EVENT for unsubscribing all events at once. + + + + V4L2_EVENT_VSYNC + 1 + This event is triggered on the vertical sync. + This event has a &v4l2-event-vsync; associated with it. + + + + V4L2_EVENT_EOS + 2 + This event is triggered when the end of a stream is reached. + This is typically used with MPEG decoders to report to the application + when the last of the MPEG stream has been decoded. + + + + V4L2_EVENT_CTRL + 3 + This event requires that the id + matches the control ID from which you want to receive events. + This event is triggered if the control's value changes, if a + button control is pressed or if the control's flags change. + This event has a &v4l2-event-ctrl; associated with it. This struct + contains much of the same information as &v4l2-queryctrl; and + &v4l2-control;. + + If the event is generated due to a call to &VIDIOC-S-CTRL; or + &VIDIOC-S-EXT-CTRLS;, then the event will not be sent to + the file handle that called the ioctl function. This prevents + nasty feedback loops. If you do want to get the + event, then set the V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK + flag. + + + This event type will ensure that no information is lost when + more events are raised than there is room internally. In that + case the &v4l2-event-ctrl; of the second-oldest event is kept, + but the changes field of the + second-oldest event is ORed with the changes + field of the oldest event. + + + + V4L2_EVENT_PRIVATE_START + 0x08000000 + Base event number for driver-private events. + + + +
+ + + Event Flags + + &cs-def; + + + V4L2_EVENT_SUB_FL_SEND_INITIAL + 0x0001 + When this event is subscribed an initial event will be sent + containing the current status. This only makes sense for events + that are triggered by a status change such as V4L2_EVENT_CTRL. + Other events will ignore this flag. + + + V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK + 0x0002 + If set, then events directly caused by an ioctl will also be sent to + the filehandle that called that ioctl. For example, changing a control using + &VIDIOC-S-CTRL; will cause a V4L2_EVENT_CTRL to be sent back to that same + filehandle. Normally such events are suppressed to prevent feedback loops + where an application changes a control to a one value and then another, and + then receives an event telling it that that control has changed to the first + value. + + Since it can't tell whether that event was caused by another application + or by the &VIDIOC-S-CTRL; call it is hard to decide whether to set the + control to the value in the event, or ignore it. + + Think carefully when you set this flag so you won't get into situations + like that. + + + + +
+ + + struct <structname>v4l2_event_vsync</structname> + + &cs-str; + + + __u8 + field + The upcoming field. See &v4l2-field;. + + + +
+ + + struct <structname>v4l2_event_ctrl</structname> + + &cs-str; + + + __u32 + changes + + A bitmask that tells what has changed. See . + + + __u32 + type + + The type of the control. See &v4l2-ctrl-type;. + + + union (anonymous) + + + + + + + __s32 + value + The 32-bit value of the control for 32-bit control types. + This is 0 for string controls since the value of a string + cannot be passed using &VIDIOC-DQEVENT;. + + + + __s64 + value64 + The 64-bit value of the control for 64-bit control types. + + + __u32 + flags + + The control flags. See . + + + __s32 + minimum + + The minimum value of the control. See &v4l2-queryctrl;. + + + __s32 + maximum + + The maximum value of the control. See &v4l2-queryctrl;. + + + __s32 + step + + The step value of the control. See &v4l2-queryctrl;. + + + __s32 + default_value + + The default value value of the control. See &v4l2-queryctrl;. + + + +
+ + + Changes + + &cs-def; + + + V4L2_EVENT_CTRL_CH_VALUE + 0x0001 + This control event was triggered because the value of the control + changed. Special case: if a button control is pressed, then this + event is sent as well, even though there is not explicit value + associated with a button control. + + + V4L2_EVENT_CTRL_CH_FLAGS + 0x0002 + This control event was triggered because the control flags + changed. + + + +
+
+ + &return-value; + +
diff --git a/Documentation/DocBook/media/vbi_525.gif.b64 b/Documentation/DocBook/media/vbi_525.gif.b64 new file mode 100644 index 0000000000000000000000000000000000000000..d5dcf06f2aef6e30519b8213472241f5f1b08c2f --- /dev/null +++ b/Documentation/DocBook/media/vbi_525.gif.b64 @@ -0,0 +1,84 @@ +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 +E9gqF8bNWgAAOw== diff --git a/Documentation/DocBook/media/vbi_625.gif.b64 b/Documentation/DocBook/media/vbi_625.gif.b64 new file mode 100644 index 0000000000000000000000000000000000000000..831f49a028218c0abff9af46b3f692c98cde6c44 --- /dev/null +++ b/Documentation/DocBook/media/vbi_625.gif.b64 @@ -0,0 +1,90 @@ +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 +0Adtyay8rcRcXsY8yW56buKsptPTzwkX0C6Xzx03zy1MzcccngxdcfDcbNE8yyatziSdbSFdzgX9 +yxqdaRxdZIpm0b/+iaY+PcgeJs2UEW3KjKeQGMmPDM2cHNHJbMv1DNKAbMpYLNKJ2kH1I9W5TNWk +nNWwTHJ9M9SKnNDL7Mgq7YpevdTa/NJuUNRPjXNvbWQKt3NwPdc8nSNhjRdtTc9wqtQOjdZ+PclN +jc4TrdBy/dV0bdcjp62SZNYEdtdr3RF6jdKH2s6VLYqN/cuCDdOETdYX2G6f7dmGfdg3F9c7gtex +FdOXvNCWrV6sDZF3KNGqbNT6FNqKDWyiXdqkXdeL/diazdYnDdXsfNmuXWVq7duRDdznPNqJrdvM +vdu8XdG4DWan3bypTdFlTdzmNm4ufdzTbN2FbdvFLN3OvdzkHd7RF93bJf3b393ZKZ3dSY3Z2AzZ +3s3ZAhzd551mNv3Ozw3U5lHGpfPfl3NGA351Rmfgj6XHd7xYUKdZCR51rGE2vVJ1E04eAU45Fl7F +1htMGv5LHN7hXZ3EIS7iI07iJW7iJ47iKa7iK87iLe7iLw7jMS7jM07jNW7jN47jOa7jO87jPe7j +Pw7kQV68E+EQhqrAQs6aZmirzYzkQC4aAmmIygHlTS7kP0G3gRJ8VB7kAGCRbQB8uqflTu6Ci4jl +ehjmPs7laf58XB7Fau6DR56aBQAAOw== diff --git a/Documentation/DocBook/media/vbi_hsync.gif.b64 b/Documentation/DocBook/media/vbi_hsync.gif.b64 new file mode 100644 index 0000000000000000000000000000000000000000..cdafabed5c111cd3bbc23c7e0028ea71a56f4138 --- /dev/null +++ b/Documentation/DocBook/media/vbi_hsync.gif.b64 @@ -0,0 +1,43 @@ +R0lGODlhBwHJAOcAAAAAAAEBAQICAgMDAwQEBAUFBQYGBgcHBwgICAkJCQoKCgsLCwwMDA0NDQ4O +Dg8PDxAQEBERERISEhMTExQUFBUVFRYWFhcXFxgYGBkZGRoaGhsbGxwcHB0dHR4eHh8fHyAgICEh +ISIiIiMjIyQkJCUlJSYmJicnJygoKCkpKSoqKisrKywsLC0tLS4uLi8vLzAwMDExMTIyMjMzMzQ0 +NDU1NTY2Njc3Nzg4ODk5OTo6Ojs7Ozw8PD09PT4+Pj8/P0BAQEFBQUJCQkNDQ0REREVFRUZGRkdH +R0hISElJSUpKSktLS0xMTE1NTU5OTk9PT1BQUFFRUVJSUlNTU1RUVFVVVVZWVldXV1hYWFlZWVpa +WltbW1xcXF1dXV5eXl9fX2BgYGFhYWJiYmNjY2RkZGVlZWZmZmdnZ2hoaGlpaWpqamtra2xsbG1t +bW5ubm9vb3BwcHFxcXJycnNzc3R0dHV1dXZ2dnd3d3h4eHl5eXp6ent7e3x8fH19fX5+fn9/f4CA +gIGBgYKCgoODg4SEhIWFhYaGhoeHh4iIiImJiYqKiouLi4yMjI2NjY6Ojo+Pj5CQkJGRkZKSkpOT +k5SUlJWVlZaWlpeXl5iYmJmZmZqampubm5ycnJ2dnZ6enp+fn6CgoKGhoaKioqOjo6SkpKWlpaam +pqenp6ioqKmpqaqqqqurq6ysrK2tra6urq+vr7CwsLGxsbKysrOzs7S0tLW1tba2tre3t7i4uLm5 +ubq6uru7u7y8vL29vb6+vr+/v8DAwMHBwcLCwsPDw8TExMXFxcbGxsfHx8jIyMnJycrKysvLy8zM +zM3Nzc7Ozs/Pz9DQ0NHR0dLS0tPT09TU1NXV1dbW1tfX19jY2NnZ2dra2tvb29zc3N3d3d7e3t/f +3+Dg4OHh4eLi4uPj4+Tk5OXl5ebm5ufn5+jo6Onp6erq6uvr6+zs7O3t7e7u7u/v7/Dw8PHx8fLy +8vPz8/T09PX19fb29vf39/j4+Pn5+fr6+vv7+/z8/P39/f7+/v///ywAAAAABwHJAAAI/gD/CRxI +sKDBgwgTKlzIsKHDhxAjSpxIsaLFixgzatzIsaPHjyBDihxJsqTJkyhTqlzJsqXLlzBjypxJs6bN +mzhz6tzJs6fPn0CDCh1KtKjRo0iTKl3KtKnTp1CjSp1KtarVqyQBYN1aVSvXr1C9gh2rVOxCsV4B +mE2b0GxDt2TjtnWo9l9du2rrar2bl+BavQL3ApZLeC5du3j77g2MF/FAtIv1AoZb+Gfey5gza97M +ua/ByJ4XI8b8+PHl0ZkrE6XsuCDr1xD5ip7d2m9pv6IZqxYK+zPC3g/T0mabGLdk4YEH7wYK3PZB +yqyXSw/++3l139OzS4R+Hbtr7eCp/nv/bp18+PMKuZcfj7792fXm47ufz/52fd308zu/X3u/fv3N ++Sfgf/MFaJ98BLpnIH4IJojegv0d6GB7EEI4oXYVdnfhgxoOyOCG4WXIH4jTidggiSV2KOGHKGa3 +oIUtqvaiijEuNyN8NUp344g5EqYef9H1KNePJwYpJFlEehjhkT7iuCKLTMZl4olRgjWlklV+deWT +WWpJ45JgdrnVllCKOeaXMJrZFZpfqmkVmWG6SRWcRsoZFZl12hkWmzxemCdXeAr555lOgjnof4de +tSOVG0KWaFl3GVponH52ZumlmGaq6aaY0pjmhJppmRqQbTaKm6gewgnio2uSOumq/jpO+qmDrE5F +p6AtSZZeSrf2WOtEoZEmm2C/Astnn6CapKtjbClWZki95lhsbLcRtxmlHkVb47TBWcuYcGvxeiyj +fp7kGbOJEZscStrGyK1T7bb4blPxojgvU4Hiulu+vto4Lpck3rvUoljCuq+npZp6cKGz0uovwwmX +u3CRESc7sZINJyhwWbJW7PDFXGZM4MZI1WsvyCF7rDHKZYqMKMuSvmqwS5yOypHJAcP0K8k4z5xr +RTz/C7DPLO2crdDPEr2S0R31rDDNQB/dMbISQ01R0FOT+/TPV0vtqtZVc21s0wjLLONFJG8XNdkQ +y5z2UNy+TW3XbN8Ho9xBxa3z/to3lz0i3nljBPhbfG+UZMoqG5db2+KJ9O7gDDHd99dUstpscsgR +x6CzqC0O0uN70z05xVlHdNpwgvUHGWrFef5RppGHPjawNddue3nB5nYufsKmu/vrhL/3kuRqq1Tr +6pd/G+6HymGLdvC7Dl+46cYD7aywoSleXGOtj5RnnZALP3vx7Bb2J/iyk6++subTZanz2ZJ2te2R +st8+9NaFHx/x1Jff5GFz0Z9/+Dc3c9EnSK4ryfLG1z89GaY6AjwQARvnQLfBr24XpFrizGSk+tlv +aOJbXwULxj3/gTB6DBwhCD2oQLBtkIR66mAEVTe9AqqQhCzMigvNhsIbrnCG/m6ZIAB9+MPqwfCB +IryhDI14QiQ2kIiUyqH3dqhBHtoJfSZs4gu16CYsGpCKYDyinLz4QS5W8YwcjF0WkxbCJxKRjC0M +oxnlmCU46tA19BPiCO04xZjM8IBq/GL63hjIMloNitiS4uv+aMUxRk5/ihQXIhMJSUaiUUzgq6RM +LEmhR5qLk2LsoieVBco5YnKUCiwlG2OIyqyoMoNpPIsm/TjJRMKya698JYZiB7kELq2W6OvlLT8H +TF62MJfM+R3+lnnIAB5zk8zBHOZks7/BqEuXwXwmLS1DzestDnmNud5MsqlDZPKGWMkzT+9CBc33 +5PGd8IynPOfJwkilLp37/gniN8dZyDgOcienCadudnc6anavnT30p/SKokvH9fOO/+RmqxIK0YUi +EosBNVz2tnnRR9KzUxyFYjAzqpHehZSQbdxYEBEqUhcVM0WTbGhNZBor+7xNj8SMaT7TJc1Tgcug +Bf2LNZnlKODp1KYCbR64ujcZ0OBxe5FR3jAfqsSdNiujucMnPnl3uaxiraNI3ep3hro8161uNLbB +G00fNk3abG+aAiXqcKqlGG8Oy6hgLang+HnUjERyiBFV4VpZitKa5rWEgKJjldgpKs5d9KOQjeym +XkrSMdnzpYatpWY3y1l6NXGB3RlsZ9eDzp7ydKmnW1dAlTnaQ94zruEkS2tUnfra1iIUdRvlHueu +iS7N2daic1VncEEz3N/6MbVyNU1TV0tUdL3VuF6aKnQhJdrpWve62M2udrfL3e5697vgDa94x0ve +8lIkIAA7 diff --git a/Documentation/DocBook/media.tmpl b/Documentation/DocBook/media_api.tmpl similarity index 89% rename from Documentation/DocBook/media.tmpl rename to Documentation/DocBook/media_api.tmpl index 88f2cc680cc2abd4ef168e3ba32c4948fe85f030..4e8e8985cc1722a5594efdb61c2c0a5af1294929 100644 --- a/Documentation/DocBook/media.tmpl +++ b/Documentation/DocBook/media_api.tmpl @@ -8,7 +8,8 @@ open()."> 2C"> -Return ValueOn success 0 is returned, on error -1 and the errno variable is set appropriately:"> +Return ValueOn success 0 is returned, on error -1 and the errno variable is set appropriately. The generic error codes are described at the Generic Error Codes chapter."> +RETURN VALUEOn success 0 is returned, on error -1 and the errno variable is set appropriately. The generic error codes are described at the Generic Error Codes chapter."> 2"> @@ -110,6 +111,11 @@ Foundation. A copy of the license is included in the chapter entitled &sub-media-controller; + +&sub-gen-errors; + + + &sub-fdl-appendix; diff --git a/Documentation/DocBook/v4l/bayer.pdf b/Documentation/DocBook/v4l/bayer.pdf deleted file mode 100644 index 905e60e6cd429f026afdfa6fb4dab3f1683adb8a..0000000000000000000000000000000000000000 Binary files a/Documentation/DocBook/v4l/bayer.pdf and /dev/null differ diff --git a/Documentation/DocBook/v4l/bayer.png b/Documentation/DocBook/v4l/bayer.png deleted file mode 100644 index 9b15fb22e8173c83c3da6df73cd7cdc7d8f41736..0000000000000000000000000000000000000000 Binary files a/Documentation/DocBook/v4l/bayer.png and /dev/null differ diff --git a/Documentation/DocBook/v4l/crop.gif b/Documentation/DocBook/v4l/crop.gif deleted file mode 100644 index 3b9e7d836d4b8a685e76ec6412fc28c9f5c16f27..0000000000000000000000000000000000000000 Binary files a/Documentation/DocBook/v4l/crop.gif and /dev/null differ diff --git a/Documentation/DocBook/v4l/dev-event.xml b/Documentation/DocBook/v4l/dev-event.xml deleted file mode 100644 index be5a98fb4fabb2e43c4355142a3216fb79d0407e..0000000000000000000000000000000000000000 --- a/Documentation/DocBook/v4l/dev-event.xml +++ /dev/null @@ -1,31 +0,0 @@ - Event Interface - - The V4L2 event interface provides means for user to get - immediately notified on certain conditions taking place on a device. - This might include start of frame or loss of signal events, for - example. - - - To receive events, the events the user is interested in first must - be subscribed using the &VIDIOC-SUBSCRIBE-EVENT; ioctl. Once an event is - subscribed, the events of subscribed types are dequeueable using the - &VIDIOC-DQEVENT; ioctl. Events may be unsubscribed using - VIDIOC_UNSUBSCRIBE_EVENT ioctl. The special event type V4L2_EVENT_ALL may - be used to unsubscribe all the events the driver supports. - - The event subscriptions and event queues are specific to file - handles. Subscribing an event on one file handle does not affect - other file handles. - - - The information on dequeueable events is obtained by using select or - poll system calls on video devices. The V4L2 events use POLLPRI events on - poll system call and exceptions on select system call. - - diff --git a/Documentation/DocBook/v4l/fieldseq_bt.gif b/Documentation/DocBook/v4l/fieldseq_bt.gif deleted file mode 100644 index 60e8569a76c92e7ab45068306dc736771fa3a61e..0000000000000000000000000000000000000000 Binary files a/Documentation/DocBook/v4l/fieldseq_bt.gif and /dev/null differ diff --git a/Documentation/DocBook/v4l/fieldseq_tb.gif b/Documentation/DocBook/v4l/fieldseq_tb.gif deleted file mode 100644 index 718492f1cfc703e6553c3b0e2afc4b269258412b..0000000000000000000000000000000000000000 Binary files a/Documentation/DocBook/v4l/fieldseq_tb.gif and /dev/null differ diff --git a/Documentation/DocBook/v4l/func-ioctl.xml b/Documentation/DocBook/v4l/func-ioctl.xml deleted file mode 100644 index b60fd37a62953961284e7bf6caca695417a19a7f..0000000000000000000000000000000000000000 --- a/Documentation/DocBook/v4l/func-ioctl.xml +++ /dev/null @@ -1,145 +0,0 @@ - - - V4L2 ioctl() - &manvol; - - - - v4l2-ioctl - Program a V4L2 device - - - - - #include <sys/ioctl.h> - - int ioctl - int fd - int request - void *argp - - - - - - Arguments - - - - fd - - &fd; - - - - request - - V4L2 ioctl request code as defined in the videodev2.h header file, for example -VIDIOC_QUERYCAP. - - - - argp - - Pointer to a function parameter, usually a structure. - - - - - - - Description - - The ioctl() function is used to program -V4L2 devices. The argument fd must be an open -file descriptor. An ioctl request has encoded -in it whether the argument is an input, output or read/write -parameter, and the size of the argument argp in -bytes. Macros and defines specifying V4L2 ioctl requests are located -in the videodev2.h header file. -Applications should use their own copy, not include the version in the -kernel sources on the system they compile on. All V4L2 ioctl requests, -their respective function and parameters are specified in . - - - - Return Value - - On success the ioctl() function returns -0 and does not reset the -errno variable. On failure --1 is returned, when the ioctl takes an -output or read/write parameter it remains unmodified, and the -errno variable is set appropriately. See below for -possible error codes. Generic errors like EBADF -or EFAULT are not listed in the sections -discussing individual ioctl requests. - Note ioctls may return undefined error codes. Since errors -may have side effects such as a driver reset applications should -abort on unexpected errors. - - - - EBADF - - fd is not a valid open file -descriptor. - - - - EBUSY - - The property cannot be changed right now. Typically -this error code is returned when I/O is in progress or the driver -supports multiple opens and another process locked the property. - - - - EFAULT - - argp references an inaccessible -memory area. - - - - ENOTTY - - fd is not associated with a -character special device. - - - - EINVAL - - The request or the data pointed -to by argp is not valid. This is a very common -error code, see the individual ioctl requests listed in for actual causes. - - - - ENOMEM - - Not enough physical or virtual memory was available to -complete the request. - - - - ERANGE - - The application attempted to set a control with the -&VIDIOC-S-CTRL; ioctl to a value which is out of bounds. - - - - - - - diff --git a/Documentation/DocBook/v4l/nv12mt.gif b/Documentation/DocBook/v4l/nv12mt.gif deleted file mode 100644 index ef2d4cf8367b97293eb9139de0f33d0a2ac236be..0000000000000000000000000000000000000000 Binary files a/Documentation/DocBook/v4l/nv12mt.gif and /dev/null differ diff --git a/Documentation/DocBook/v4l/nv12mt_example.gif b/Documentation/DocBook/v4l/nv12mt_example.gif deleted file mode 100644 index df81d68108eeb66569417b475984aa634385eebb..0000000000000000000000000000000000000000 Binary files a/Documentation/DocBook/v4l/nv12mt_example.gif and /dev/null differ diff --git a/Documentation/DocBook/v4l/pipeline.png b/Documentation/DocBook/v4l/pipeline.png deleted file mode 100644 index f19b86c2c24d07d5ae437820944d25489a447d7a..0000000000000000000000000000000000000000 Binary files a/Documentation/DocBook/v4l/pipeline.png and /dev/null differ diff --git a/Documentation/DocBook/v4l/vbi_525.gif b/Documentation/DocBook/v4l/vbi_525.gif deleted file mode 100644 index 5580b690d504f388f5c62f730c45e09999da1341..0000000000000000000000000000000000000000 Binary files a/Documentation/DocBook/v4l/vbi_525.gif and /dev/null differ diff --git a/Documentation/DocBook/v4l/vbi_625.gif b/Documentation/DocBook/v4l/vbi_625.gif deleted file mode 100644 index 34e3251983c4918ac5457a27d524ab1eaa54626a..0000000000000000000000000000000000000000 Binary files a/Documentation/DocBook/v4l/vbi_625.gif and /dev/null differ diff --git a/Documentation/DocBook/v4l/vbi_hsync.gif b/Documentation/DocBook/v4l/vbi_hsync.gif deleted file mode 100644 index b02434d3b356c4646c47dc85dd662daf54202cdf..0000000000000000000000000000000000000000 Binary files a/Documentation/DocBook/v4l/vbi_hsync.gif and /dev/null differ diff --git a/Documentation/DocBook/v4l/videodev2.h.xml b/Documentation/DocBook/v4l/videodev2.h.xml deleted file mode 100644 index c50536a4f596150af92dd64072e65f25b8dfd892..0000000000000000000000000000000000000000 --- a/Documentation/DocBook/v4l/videodev2.h.xml +++ /dev/null @@ -1,1946 +0,0 @@ - -/* - * Video for Linux Two header file - * - * Copyright (C) 1999-2007 the contributors - * - * 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. - * - * Alternatively you can redistribute this file under the terms of the - * BSD license as stated below: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. The names of its contributors may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Header file for v4l or V4L2 drivers and applications - * with public API. - * All kernel-specific stuff were moved to media/v4l2-dev.h, so - * no #if __KERNEL tests are allowed here - * - * See http://linuxtv.org for more info - * - * Author: Bill Dirks <bill@thedirks.org> - * Justin Schoeman - * Hans Verkuil <hverkuil@xs4all.nl> - * et al. - */ -#ifndef __LINUX_VIDEODEV2_H -#define __LINUX_VIDEODEV2_H - -#ifdef __KERNEL__ -#include <linux/time.h> /* need struct timeval */ -#else -#include <sys/time.h> -#endif -#include <linux/compiler.h> -#include <linux/ioctl.h> -#include <linux/types.h> - -/* - * Common stuff for both V4L1 and V4L2 - * Moved from videodev.h - */ -#define VIDEO_MAX_FRAME 32 -#define VIDEO_MAX_PLANES 8 - -#ifndef __KERNEL__ - -/* These defines are V4L1 specific and should not be used with the V4L2 API! - They will be removed from this header in the future. */ - -#define VID_TYPE_CAPTURE 1 /* Can capture */ -#define VID_TYPE_TUNER 2 /* Can tune */ -#define VID_TYPE_TELETEXT 4 /* Does teletext */ -#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ -#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ -#define VID_TYPE_CLIPPING 32 /* Can clip */ -#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ -#define VID_TYPE_SCALES 128 /* Scalable */ -#define VID_TYPE_MONOCHROME 256 /* Monochrome only */ -#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ -#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ -#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ -#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ -#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ -#endif - -/* - * M I S C E L L A N E O U S - */ - -/* Four-character-code (FOURCC) */ -#define v4l2_fourcc(a, b, c, d)\ - ((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24)) - -/* - * E N U M S - */ -enum v4l2_field { - V4L2_FIELD_ANY = 0, /* driver can choose from none, - top, bottom, interlaced - depending on whatever it thinks - is approximate ... */ - V4L2_FIELD_NONE = 1, /* this device has no fields ... */ - V4L2_FIELD_TOP = 2, /* top field only */ - V4L2_FIELD_BOTTOM = 3, /* bottom field only */ - V4L2_FIELD_INTERLACED = 4, /* both fields interlaced */ - V4L2_FIELD_SEQ_TB = 5, /* both fields sequential into one - buffer, top-bottom order */ - V4L2_FIELD_SEQ_BT = 6, /* same as above + bottom-top order */ - V4L2_FIELD_ALTERNATE = 7, /* both fields alternating into - separate buffers */ - V4L2_FIELD_INTERLACED_TB = 8, /* both fields interlaced, top field - first and the top field is - transmitted first */ - V4L2_FIELD_INTERLACED_BT = 9, /* both fields interlaced, top field - first and the bottom field is - transmitted first */ -}; -#define V4L2_FIELD_HAS_TOP(field) \ - ((field) == V4L2_FIELD_TOP ||\ - (field) == V4L2_FIELD_INTERLACED ||\ - (field) == V4L2_FIELD_INTERLACED_TB ||\ - (field) == V4L2_FIELD_INTERLACED_BT ||\ - (field) == V4L2_FIELD_SEQ_TB ||\ - (field) == V4L2_FIELD_SEQ_BT) -#define V4L2_FIELD_HAS_BOTTOM(field) \ - ((field) == V4L2_FIELD_BOTTOM ||\ - (field) == V4L2_FIELD_INTERLACED ||\ - (field) == V4L2_FIELD_INTERLACED_TB ||\ - (field) == V4L2_FIELD_INTERLACED_BT ||\ - (field) == V4L2_FIELD_SEQ_TB ||\ - (field) == V4L2_FIELD_SEQ_BT) -#define V4L2_FIELD_HAS_BOTH(field) \ - ((field) == V4L2_FIELD_INTERLACED ||\ - (field) == V4L2_FIELD_INTERLACED_TB ||\ - (field) == V4L2_FIELD_INTERLACED_BT ||\ - (field) == V4L2_FIELD_SEQ_TB ||\ - (field) == V4L2_FIELD_SEQ_BT) - -enum v4l2_buf_type { - V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, - V4L2_BUF_TYPE_VIDEO_OUTPUT = 2, - V4L2_BUF_TYPE_VIDEO_OVERLAY = 3, - V4L2_BUF_TYPE_VBI_CAPTURE = 4, - V4L2_BUF_TYPE_VBI_OUTPUT = 5, - V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6, - V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7, -#if 1 - /* Experimental */ - V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8, -#endif - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9, - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE = 10, - V4L2_BUF_TYPE_PRIVATE = 0x80, -}; - -#define V4L2_TYPE_IS_MULTIPLANAR(type) \ - ((type) == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE \ - || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - -#define V4L2_TYPE_IS_OUTPUT(type) \ - ((type) == V4L2_BUF_TYPE_VIDEO_OUTPUT \ - || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE \ - || (type) == V4L2_BUF_TYPE_VIDEO_OVERLAY \ - || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY \ - || (type) == V4L2_BUF_TYPE_VBI_OUTPUT \ - || (type) == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) - -enum v4l2_tuner_type { - V4L2_TUNER_RADIO = 1, - V4L2_TUNER_ANALOG_TV = 2, - V4L2_TUNER_DIGITAL_TV = 3, -}; - -enum v4l2_memory { - V4L2_MEMORY_MMAP = 1, - V4L2_MEMORY_USERPTR = 2, - V4L2_MEMORY_OVERLAY = 3, -}; - -/* see also http://vektor.theorem.ca/graphics/ycbcr/ */ -enum v4l2_colorspace { - /* ITU-R 601 -- broadcast NTSC/PAL */ - V4L2_COLORSPACE_SMPTE170M = 1, - - /* 1125-Line (US) HDTV */ - V4L2_COLORSPACE_SMPTE240M = 2, - - /* HD and modern captures. */ - V4L2_COLORSPACE_REC709 = 3, - - /* broken BT878 extents (601, luma range 16-253 instead of 16-235) */ - V4L2_COLORSPACE_BT878 = 4, - - /* These should be useful. Assume 601 extents. */ - V4L2_COLORSPACE_470_SYSTEM_M = 5, - V4L2_COLORSPACE_470_SYSTEM_BG = 6, - - /* I know there will be cameras that send this. So, this is - * unspecified chromaticities and full 0-255 on each of the - * Y'CbCr components - */ - V4L2_COLORSPACE_JPEG = 7, - - /* For RGB colourspaces, this is probably a good start. */ - V4L2_COLORSPACE_SRGB = 8, -}; - -enum v4l2_priority { - V4L2_PRIORITY_UNSET = 0, /* not initialized */ - V4L2_PRIORITY_BACKGROUND = 1, - V4L2_PRIORITY_INTERACTIVE = 2, - V4L2_PRIORITY_RECORD = 3, - V4L2_PRIORITY_DEFAULT = V4L2_PRIORITY_INTERACTIVE, -}; - -struct v4l2_rect { - __s32 left; - __s32 top; - __s32 width; - __s32 height; -}; - -struct v4l2_fract { - __u32 numerator; - __u32 denominator; -}; - -/* - * D R I V E R C A P A B I L I T I E S - */ -struct v4l2_capability { - __u8 driver[16]; /* i.e.ie; "bttv" */ - __u8 card[32]; /* i.e.ie; "Hauppauge WinTV" */ - __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */ - __u32 version; /* should use KERNEL_VERSION() */ - __u32 capabilities; /* Device capabilities */ - __u32 reserved[4]; -}; - -/* Values for 'capabilities' field */ -#define V4L2_CAP_VIDEO_CAPTURE 0x00000001 /* Is a video capture device */ -#define V4L2_CAP_VIDEO_OUTPUT 0x00000002 /* Is a video output device */ -#define V4L2_CAP_VIDEO_OVERLAY 0x00000004 /* Can do video overlay */ -#define V4L2_CAP_VBI_CAPTURE 0x00000010 /* Is a raw VBI capture device */ -#define V4L2_CAP_VBI_OUTPUT 0x00000020 /* Is a raw VBI output device */ -#define V4L2_CAP_SLICED_VBI_CAPTURE 0x00000040 /* Is a sliced VBI capture device */ -#define V4L2_CAP_SLICED_VBI_OUTPUT 0x00000080 /* Is a sliced VBI output device */ -#define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */ -#define V4L2_CAP_VIDEO_OUTPUT_OVERLAY 0x00000200 /* Can do video output overlay */ -#define V4L2_CAP_HW_FREQ_SEEK 0x00000400 /* Can do hardware frequency seek */ -#define V4L2_CAP_RDS_OUTPUT 0x00000800 /* Is an RDS encoder */ - -/* Is a video capture device that supports multiplanar formats */ -#define V4L2_CAP_VIDEO_CAPTURE_MPLANE 0x00001000 -/* Is a video output device that supports multiplanar formats */ -#define V4L2_CAP_VIDEO_OUTPUT_MPLANE 0x00002000 - -#define V4L2_CAP_TUNER 0x00010000 /* has a tuner */ -#define V4L2_CAP_AUDIO 0x00020000 /* has audio support */ -#define V4L2_CAP_RADIO 0x00040000 /* is a radio device */ -#define V4L2_CAP_MODULATOR 0x00080000 /* has a modulator */ - -#define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */ -#define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */ -#define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */ - -/* - * V I D E O I M A G E F O R M A T - */ -struct v4l2_pix_format { - __u32 width; - __u32 height; - __u32 pixelformat; - enum v4l2_field field; - __u32 bytesperline; /* for padding, zero if unused */ - __u32 sizeimage; - enum v4l2_colorspace colorspace; - __u32 priv; /* private data, depends on pixelformat */ -}; - -/* Pixel format FOURCC depth Description */ - -/* RGB formats */ -#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R', 'G', 'B', '1') /* 8 RGB-3-3-2 */ -#define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R', '4', '4', '4') /* 16 xxxxrrrr ggggbbbb */ -#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R', 'G', 'B', 'O') /* 16 RGB-5-5-5 */ -#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R', 'G', 'B', 'P') /* 16 RGB-5-6-5 */ -#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16 RGB-5-5-5 BE */ -#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16 RGB-5-6-5 BE */ -#define V4L2_PIX_FMT_BGR666 v4l2_fourcc('B', 'G', 'R', 'H') /* 18 BGR-6-6-6 */ -#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3') /* 24 BGR-8-8-8 */ -#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */ -#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4') /* 32 BGR-8-8-8-8 */ -#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R', 'G', 'B', '4') /* 32 RGB-8-8-8-8 */ - -/* Grey formats */ -#define V4L2_PIX_FMT_GREY v4l2_fourcc('G', 'R', 'E', 'Y') /* 8 Greyscale */ -#define V4L2_PIX_FMT_Y4 v4l2_fourcc('Y', '0', '4', ' ') /* 4 Greyscale */ -#define V4L2_PIX_FMT_Y6 v4l2_fourcc('Y', '0', '6', ' ') /* 6 Greyscale */ -#define V4L2_PIX_FMT_Y10 v4l2_fourcc('Y', '1', '0', ' ') /* 10 Greyscale */ -#define V4L2_PIX_FMT_Y16 v4l2_fourcc('Y', '1', '6', ' ') /* 16 Greyscale */ - -/* Grey bit-packed formats */ -#define V4L2_PIX_FMT_Y10BPACK v4l2_fourcc('Y', '1', '0', 'B') /* 10 Greyscale bit-packed */ - -/* Palette formats */ -#define V4L2_PIX_FMT_PAL8 v4l2_fourcc('P', 'A', 'L', '8') /* 8 8-bit palette */ - -/* Luminance+Chrominance formats */ -#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y', 'V', 'U', '9') /* 9 YVU 4:1:0 */ -#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */ -#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */ -#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y', 'Y', 'U', 'V') /* 16 YUV 4:2:2 */ -#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */ -#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16 YUV 4:2:2 */ -#define V4L2_PIX_FMT_VYUY v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16 YUV 4:2:2 */ -#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') /* 16 YVU422 planar */ -#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4', '1', '1', 'P') /* 16 YVU411 planar */ -#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y', '4', '1', 'P') /* 12 YUV 4:1:1 */ -#define V4L2_PIX_FMT_YUV444 v4l2_fourcc('Y', '4', '4', '4') /* 16 xxxxyyyy uuuuvvvv */ -#define V4L2_PIX_FMT_YUV555 v4l2_fourcc('Y', 'U', 'V', 'O') /* 16 YUV-5-5-5 */ -#define V4L2_PIX_FMT_YUV565 v4l2_fourcc('Y', 'U', 'V', 'P') /* 16 YUV-5-6-5 */ -#define V4L2_PIX_FMT_YUV32 v4l2_fourcc('Y', 'U', 'V', '4') /* 32 YUV-8-8-8-8 */ -#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y', 'U', 'V', '9') /* 9 YUV 4:1:0 */ -#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */ -#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') /* 8 8-bit color */ -#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */ -#define V4L2_PIX_FMT_M420 v4l2_fourcc('M', '4', '2', '0') /* 12 YUV 4:2:0 2 lines y, 1 line uv interleaved */ - -/* two planes -- one Y, one Cr + Cb interleaved */ -#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */ -#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */ -#define V4L2_PIX_FMT_NV16 v4l2_fourcc('N', 'V', '1', '6') /* 16 Y/CbCr 4:2:2 */ -#define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') /* 16 Y/CrCb 4:2:2 */ - -/* two non contiguous planes - one Y, one Cr + Cb interleaved */ -#define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */ -#define V4L2_PIX_FMT_NV12MT v4l2_fourcc('T', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 64x32 macroblocks */ - -/* three non contiguous planes - Y, Cb, Cr */ -#define V4L2_PIX_FMT_YUV420M v4l2_fourcc('Y', 'M', '1', '2') /* 12 YUV420 planar */ - -/* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */ -#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */ -#define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */ -#define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G') /* 8 GRGR.. BGBG.. */ -#define V4L2_PIX_FMT_SRGGB8 v4l2_fourcc('R', 'G', 'G', 'B') /* 8 RGRG.. GBGB.. */ -#define V4L2_PIX_FMT_SBGGR10 v4l2_fourcc('B', 'G', '1', '0') /* 10 BGBG.. GRGR.. */ -#define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '0') /* 10 GBGB.. RGRG.. */ -#define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10 GRGR.. BGBG.. */ -#define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '0') /* 10 RGRG.. GBGB.. */ - /* 10bit raw bayer DPCM compressed to 8 bits */ -#define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0') - /* - * 10bit raw bayer, expanded to 16 bits - * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb... - */ -#define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') /* 16 BGBG.. GRGR.. */ - -/* compressed formats */ -#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG */ -#define V4L2_PIX_FMT_JPEG v4l2_fourcc('J', 'P', 'E', 'G') /* JFIF JPEG */ -#define V4L2_PIX_FMT_DV v4l2_fourcc('d', 'v', 's', 'd') /* 1394 */ -#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4 */ - -/* Vendor-specific formats */ -#define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */ -#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W', 'N', 'V', 'A') /* Winnov hw compress */ -#define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S', '9', '1', '0') /* SN9C10x compression */ -#define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') /* SN9C20x YUV 4:2:0 */ -#define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P', 'W', 'C', '1') /* pwc older webcam */ -#define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P', 'W', 'C', '2') /* pwc newer webcam */ -#define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E', '6', '2', '5') /* ET61X251 compression */ -#define V4L2_PIX_FMT_SPCA501 v4l2_fourcc('S', '5', '0', '1') /* YUYV per line */ -#define V4L2_PIX_FMT_SPCA505 v4l2_fourcc('S', '5', '0', '5') /* YYUV per line */ -#define V4L2_PIX_FMT_SPCA508 v4l2_fourcc('S', '5', '0', '8') /* YUVY per line */ -#define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */ -#define V4L2_PIX_FMT_PAC207 v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */ -#define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */ -#define V4L2_PIX_FMT_SN9C2028 v4l2_fourcc('S', 'O', 'N', 'X') /* compressed GBRG bayer */ -#define V4L2_PIX_FMT_SQ905C v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */ -#define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */ -#define V4L2_PIX_FMT_OV511 v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */ -#define V4L2_PIX_FMT_OV518 v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */ -#define V4L2_PIX_FMT_STV0680 v4l2_fourcc('S', '6', '8', '0') /* stv0680 bayer */ -#define V4L2_PIX_FMT_TM6000 v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */ -#define V4L2_PIX_FMT_CIT_YYVYUY v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */ -#define V4L2_PIX_FMT_KONICA420 v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */ - -/* - * F O R M A T E N U M E R A T I O N - */ -struct v4l2_fmtdesc { - __u32 index; /* Format number */ - enum v4l2_buf_type type; /* buffer type */ - __u32 flags; - __u8 description[32]; /* Description string */ - __u32 pixelformat; /* Format fourcc */ - __u32 reserved[4]; -}; - -#define V4L2_FMT_FLAG_COMPRESSED 0x0001 -#define V4L2_FMT_FLAG_EMULATED 0x0002 - -#if 1 - /* Experimental Frame Size and frame rate enumeration */ -/* - * F R A M E S I Z E E N U M E R A T I O N - */ -enum v4l2_frmsizetypes { - V4L2_FRMSIZE_TYPE_DISCRETE = 1, - V4L2_FRMSIZE_TYPE_CONTINUOUS = 2, - V4L2_FRMSIZE_TYPE_STEPWISE = 3, -}; - -struct v4l2_frmsize_discrete { - __u32 width; /* Frame width [pixel] */ - __u32 height; /* Frame height [pixel] */ -}; - -struct v4l2_frmsize_stepwise { - __u32 min_width; /* Minimum frame width [pixel] */ - __u32 max_width; /* Maximum frame width [pixel] */ - __u32 step_width; /* Frame width step size [pixel] */ - __u32 min_height; /* Minimum frame height [pixel] */ - __u32 max_height; /* Maximum frame height [pixel] */ - __u32 step_height; /* Frame height step size [pixel] */ -}; - -struct v4l2_frmsizeenum { - __u32 index; /* Frame size number */ - __u32 pixel_format; /* Pixel format */ - __u32 type; /* Frame size type the device supports. */ - - union { /* Frame size */ - struct v4l2_frmsize_discrete discrete; - struct v4l2_frmsize_stepwise stepwise; - }; - - __u32 reserved[2]; /* Reserved space for future use */ -}; - -/* - * F R A M E R A T E E N U M E R A T I O N - */ -enum v4l2_frmivaltypes { - V4L2_FRMIVAL_TYPE_DISCRETE = 1, - V4L2_FRMIVAL_TYPE_CONTINUOUS = 2, - V4L2_FRMIVAL_TYPE_STEPWISE = 3, -}; - -struct v4l2_frmival_stepwise { - struct v4l2_fract min; /* Minimum frame interval [s] */ - struct v4l2_fract max; /* Maximum frame interval [s] */ - struct v4l2_fract step; /* Frame interval step size [s] */ -}; - -struct v4l2_frmivalenum { - __u32 index; /* Frame format index */ - __u32 pixel_format; /* Pixel format */ - __u32 width; /* Frame width */ - __u32 height; /* Frame height */ - __u32 type; /* Frame interval type the device supports. */ - - union { /* Frame interval */ - struct v4l2_fract discrete; - struct v4l2_frmival_stepwise stepwise; - }; - - __u32 reserved[2]; /* Reserved space for future use */ -}; -#endif - -/* - * T I M E C O D E - */ -struct v4l2_timecode { - __u32 type; - __u32 flags; - __u8 frames; - __u8 seconds; - __u8 minutes; - __u8 hours; - __u8 userbits[4]; -}; - -/* Type */ -#define V4L2_TC_TYPE_24FPS 1 -#define V4L2_TC_TYPE_25FPS 2 -#define V4L2_TC_TYPE_30FPS 3 -#define V4L2_TC_TYPE_50FPS 4 -#define V4L2_TC_TYPE_60FPS 5 - -/* Flags */ -#define V4L2_TC_FLAG_DROPFRAME 0x0001 /* "drop-frame" mode */ -#define V4L2_TC_FLAG_COLORFRAME 0x0002 -#define V4L2_TC_USERBITS_field 0x000C -#define V4L2_TC_USERBITS_USERDEFINED 0x0000 -#define V4L2_TC_USERBITS_8BITCHARS 0x0008 -/* The above is based on SMPTE timecodes */ - -struct v4l2_jpegcompression { - int quality; - - int APPn; /* Number of APP segment to be written, - * must be 0..15 */ - int APP_len; /* Length of data in JPEG APPn segment */ - char APP_data[60]; /* Data in the JPEG APPn segment. */ - - int COM_len; /* Length of data in JPEG COM segment */ - char COM_data[60]; /* Data in JPEG COM segment */ - - __u32 jpeg_markers; /* Which markers should go into the JPEG - * output. Unless you exactly know what - * you do, leave them untouched. - * Inluding less markers will make the - * resulting code smaller, but there will - * be fewer applications which can read it. - * The presence of the APP and COM marker - * is influenced by APP_len and COM_len - * ONLY, not by this property! */ - -#define V4L2_JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ -#define V4L2_JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ -#define V4L2_JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ -#define V4L2_JPEG_MARKER_COM (1<<6) /* Comment segment */ -#define V4L2_JPEG_MARKER_APP (1<<7) /* App segment, driver will - * allways use APP0 */ -}; - -/* - * M E M O R Y - M A P P I N G B U F F E R S - */ -struct v4l2_requestbuffers { - __u32 count; - enum v4l2_buf_type type; - enum v4l2_memory memory; - __u32 reserved[2]; -}; - -/** - * struct v4l2_plane - plane info for multi-planar buffers - * @bytesused: number of bytes occupied by data in the plane (payload) - * @length: size of this plane (NOT the payload) in bytes - * @mem_offset: when memory in the associated struct v4l2_buffer is - * V4L2_MEMORY_MMAP, equals the offset from the start of - * the device memory for this plane (or is a "cookie" that - * should be passed to mmap() called on the video node) - * @userptr: when memory is V4L2_MEMORY_USERPTR, a userspace pointer - * pointing to this plane - * @data_offset: offset in the plane to the start of data; usually 0, - * unless there is a header in front of the data - * - * Multi-planar buffers consist of one or more planes, e.g. an YCbCr buffer - * with two planes can have one plane for Y, and another for interleaved CbCr - * components. Each plane can reside in a separate memory buffer, or even in - * a completely separate memory node (e.g. in embedded devices). - */ -struct v4l2_plane { - __u32 bytesused; - __u32 length; - union { - __u32 mem_offset; - unsigned long userptr; - } m; - __u32 data_offset; - __u32 reserved[11]; -}; - -/** - * struct v4l2_buffer - video buffer info - * @index: id number of the buffer - * @type: buffer type (type == *_MPLANE for multiplanar buffers) - * @bytesused: number of bytes occupied by data in the buffer (payload); - * unused (set to 0) for multiplanar buffers - * @flags: buffer informational flags - * @field: field order of the image in the buffer - * @timestamp: frame timestamp - * @timecode: frame timecode - * @sequence: sequence count of this frame - * @memory: the method, in which the actual video data is passed - * @offset: for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP; - * offset from the start of the device memory for this plane, - * (or a "cookie" that should be passed to mmap() as offset) - * @userptr: for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR; - * a userspace pointer pointing to this buffer - * @planes: for multiplanar buffers; userspace pointer to the array of plane - * info structs for this buffer - * @length: size in bytes of the buffer (NOT its payload) for single-plane - * buffers (when type != *_MPLANE); number of elements in the - * planes array for multi-plane buffers - * @input: input number from which the video data has has been captured - * - * Contains data exchanged by application and driver using one of the Streaming - * I/O methods. - */ -struct v4l2_buffer { - __u32 index; - enum v4l2_buf_type type; - __u32 bytesused; - __u32 flags; - enum v4l2_field field; - struct timeval timestamp; - struct v4l2_timecode timecode; - __u32 sequence; - - /* memory location */ - enum v4l2_memory memory; - union { - __u32 offset; - unsigned long userptr; - struct v4l2_plane *planes; - } m; - __u32 length; - __u32 input; - __u32 reserved; -}; - -/* Flags for 'flags' field */ -#define V4L2_BUF_FLAG_MAPPED 0x0001 /* Buffer is mapped (flag) */ -#define V4L2_BUF_FLAG_QUEUED 0x0002 /* Buffer is queued for processing */ -#define V4L2_BUF_FLAG_DONE 0x0004 /* Buffer is ready */ -#define V4L2_BUF_FLAG_KEYFRAME 0x0008 /* Image is a keyframe (I-frame) */ -#define V4L2_BUF_FLAG_PFRAME 0x0010 /* Image is a P-frame */ -#define V4L2_BUF_FLAG_BFRAME 0x0020 /* Image is a B-frame */ -/* Buffer is ready, but the data contained within is corrupted. */ -#define V4L2_BUF_FLAG_ERROR 0x0040 -#define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */ -#define V4L2_BUF_FLAG_INPUT 0x0200 /* input field is valid */ - -/* - * O V E R L A Y P R E V I E W - */ -struct v4l2_framebuffer { - __u32 capability; - __u32 flags; -/* FIXME: in theory we should pass something like PCI device + memory - * region + offset instead of some physical address */ - void *base; - struct v4l2_pix_format fmt; -}; -/* Flags for the 'capability' field. Read only */ -#define V4L2_FBUF_CAP_EXTERNOVERLAY 0x0001 -#define V4L2_FBUF_CAP_CHROMAKEY 0x0002 -#define V4L2_FBUF_CAP_LIST_CLIPPING 0x0004 -#define V4L2_FBUF_CAP_BITMAP_CLIPPING 0x0008 -#define V4L2_FBUF_CAP_LOCAL_ALPHA 0x0010 -#define V4L2_FBUF_CAP_GLOBAL_ALPHA 0x0020 -#define V4L2_FBUF_CAP_LOCAL_INV_ALPHA 0x0040 -#define V4L2_FBUF_CAP_SRC_CHROMAKEY 0x0080 -/* Flags for the 'flags' field. */ -#define V4L2_FBUF_FLAG_PRIMARY 0x0001 -#define V4L2_FBUF_FLAG_OVERLAY 0x0002 -#define V4L2_FBUF_FLAG_CHROMAKEY 0x0004 -#define V4L2_FBUF_FLAG_LOCAL_ALPHA 0x0008 -#define V4L2_FBUF_FLAG_GLOBAL_ALPHA 0x0010 -#define V4L2_FBUF_FLAG_LOCAL_INV_ALPHA 0x0020 -#define V4L2_FBUF_FLAG_SRC_CHROMAKEY 0x0040 - -struct v4l2_clip { - struct v4l2_rect c; - struct v4l2_clip __user *next; -}; - -struct v4l2_window { - struct v4l2_rect w; - enum v4l2_field field; - __u32 chromakey; - struct v4l2_clip __user *clips; - __u32 clipcount; - void __user *bitmap; - __u8 global_alpha; -}; - -/* - * C A P T U R E P A R A M E T E R S - */ -struct v4l2_captureparm { - __u32 capability; /* Supported modes */ - __u32 capturemode; /* Current mode */ - struct v4l2_fract timeperframe; /* Time per frame in .1us units */ - __u32 extendedmode; /* Driver-specific extensions */ - __u32 readbuffers; /* # of buffers for read */ - __u32 reserved[4]; -}; - -/* Flags for 'capability' and 'capturemode' fields */ -#define V4L2_MODE_HIGHQUALITY 0x0001 /* High quality imaging mode */ -#define V4L2_CAP_TIMEPERFRAME 0x1000 /* timeperframe field is supported */ - -struct v4l2_outputparm { - __u32 capability; /* Supported modes */ - __u32 outputmode; /* Current mode */ - struct v4l2_fract timeperframe; /* Time per frame in seconds */ - __u32 extendedmode; /* Driver-specific extensions */ - __u32 writebuffers; /* # of buffers for write */ - __u32 reserved[4]; -}; - -/* - * I N P U T I M A G E C R O P P I N G - */ -struct v4l2_cropcap { - enum v4l2_buf_type type; - struct v4l2_rect bounds; - struct v4l2_rect defrect; - struct v4l2_fract pixelaspect; -}; - -struct v4l2_crop { - enum v4l2_buf_type type; - struct v4l2_rect c; -}; - -/* - * A N A L O G V I D E O S T A N D A R D - */ - -typedef __u64 v4l2_std_id; - -/* one bit for each */ -#define V4L2_STD_PAL_B ((v4l2_std_id)0x00000001) -#define V4L2_STD_PAL_B1 ((v4l2_std_id)0x00000002) -#define V4L2_STD_PAL_G ((v4l2_std_id)0x00000004) -#define V4L2_STD_PAL_H ((v4l2_std_id)0x00000008) -#define V4L2_STD_PAL_I ((v4l2_std_id)0x00000010) -#define V4L2_STD_PAL_D ((v4l2_std_id)0x00000020) -#define V4L2_STD_PAL_D1 ((v4l2_std_id)0x00000040) -#define V4L2_STD_PAL_K ((v4l2_std_id)0x00000080) - -#define V4L2_STD_PAL_M ((v4l2_std_id)0x00000100) -#define V4L2_STD_PAL_N ((v4l2_std_id)0x00000200) -#define V4L2_STD_PAL_Nc ((v4l2_std_id)0x00000400) -#define V4L2_STD_PAL_60 ((v4l2_std_id)0x00000800) - -#define V4L2_STD_NTSC_M ((v4l2_std_id)0x00001000) -#define V4L2_STD_NTSC_M_JP ((v4l2_std_id)0x00002000) -#define V4L2_STD_NTSC_443 ((v4l2_std_id)0x00004000) -#define V4L2_STD_NTSC_M_KR ((v4l2_std_id)0x00008000) - -#define V4L2_STD_SECAM_B ((v4l2_std_id)0x00010000) -#define V4L2_STD_SECAM_D ((v4l2_std_id)0x00020000) -#define V4L2_STD_SECAM_G ((v4l2_std_id)0x00040000) -#define V4L2_STD_SECAM_H ((v4l2_std_id)0x00080000) -#define V4L2_STD_SECAM_K ((v4l2_std_id)0x00100000) -#define V4L2_STD_SECAM_K1 ((v4l2_std_id)0x00200000) -#define V4L2_STD_SECAM_L ((v4l2_std_id)0x00400000) -#define V4L2_STD_SECAM_LC ((v4l2_std_id)0x00800000) - -/* ATSC/HDTV */ -#define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000) -#define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000) - -/* FIXME: - Although std_id is 64 bits, there is an issue on PPC32 architecture that - makes switch(__u64) to break. So, there's a hack on v4l2-common.c rounding - this value to 32 bits. - As, currently, the max value is for V4L2_STD_ATSC_16_VSB (30 bits wide), - it should work fine. However, if needed to add more than two standards, - v4l2-common.c should be fixed. - */ - -/* some merged standards */ -#define V4L2_STD_MN (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC) -#define V4L2_STD_B (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B) -#define V4L2_STD_GH (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H) -#define V4L2_STD_DK (V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK) - -/* some common needed stuff */ -#define V4L2_STD_PAL_BG (V4L2_STD_PAL_B |\ - V4L2_STD_PAL_B1 |\ - V4L2_STD_PAL_G) -#define V4L2_STD_PAL_DK (V4L2_STD_PAL_D |\ - V4L2_STD_PAL_D1 |\ - V4L2_STD_PAL_K) -#define V4L2_STD_PAL (V4L2_STD_PAL_BG |\ - V4L2_STD_PAL_DK |\ - V4L2_STD_PAL_H |\ - V4L2_STD_PAL_I) -#define V4L2_STD_NTSC (V4L2_STD_NTSC_M |\ - V4L2_STD_NTSC_M_JP |\ - V4L2_STD_NTSC_M_KR) -#define V4L2_STD_SECAM_DK (V4L2_STD_SECAM_D |\ - V4L2_STD_SECAM_K |\ - V4L2_STD_SECAM_K1) -#define V4L2_STD_SECAM (V4L2_STD_SECAM_B |\ - V4L2_STD_SECAM_G |\ - V4L2_STD_SECAM_H |\ - V4L2_STD_SECAM_DK |\ - V4L2_STD_SECAM_L |\ - V4L2_STD_SECAM_LC) - -#define V4L2_STD_525_60 (V4L2_STD_PAL_M |\ - V4L2_STD_PAL_60 |\ - V4L2_STD_NTSC |\ - V4L2_STD_NTSC_443) -#define V4L2_STD_625_50 (V4L2_STD_PAL |\ - V4L2_STD_PAL_N |\ - V4L2_STD_PAL_Nc |\ - V4L2_STD_SECAM) -#define V4L2_STD_ATSC (V4L2_STD_ATSC_8_VSB |\ - V4L2_STD_ATSC_16_VSB) - -#define V4L2_STD_UNKNOWN 0 -#define V4L2_STD_ALL (V4L2_STD_525_60 |\ - V4L2_STD_625_50) - -struct v4l2_standard { - __u32 index; - v4l2_std_id id; - __u8 name[24]; - struct v4l2_fract frameperiod; /* Frames, not fields */ - __u32 framelines; - __u32 reserved[4]; -}; - -/* - * V I D E O T I M I N G S D V P R E S E T - */ -struct v4l2_dv_preset { - __u32 preset; - __u32 reserved[4]; -}; - -/* - * D V P R E S E T S E N U M E R A T I O N - */ -struct v4l2_dv_enum_preset { - __u32 index; - __u32 preset; - __u8 name[32]; /* Name of the preset timing */ - __u32 width; - __u32 height; - __u32 reserved[4]; -}; - -/* - * D V P R E S E T V A L U E S - */ -#define V4L2_DV_INVALID 0 -#define V4L2_DV_480P59_94 1 /* BT.1362 */ -#define V4L2_DV_576P50 2 /* BT.1362 */ -#define V4L2_DV_720P24 3 /* SMPTE 296M */ -#define V4L2_DV_720P25 4 /* SMPTE 296M */ -#define V4L2_DV_720P30 5 /* SMPTE 296M */ -#define V4L2_DV_720P50 6 /* SMPTE 296M */ -#define V4L2_DV_720P59_94 7 /* SMPTE 274M */ -#define V4L2_DV_720P60 8 /* SMPTE 274M/296M */ -#define V4L2_DV_1080I29_97 9 /* BT.1120/ SMPTE 274M */ -#define V4L2_DV_1080I30 10 /* BT.1120/ SMPTE 274M */ -#define V4L2_DV_1080I25 11 /* BT.1120 */ -#define V4L2_DV_1080I50 12 /* SMPTE 296M */ -#define V4L2_DV_1080I60 13 /* SMPTE 296M */ -#define V4L2_DV_1080P24 14 /* SMPTE 296M */ -#define V4L2_DV_1080P25 15 /* SMPTE 296M */ -#define V4L2_DV_1080P30 16 /* SMPTE 296M */ -#define V4L2_DV_1080P50 17 /* BT.1120 */ -#define V4L2_DV_1080P60 18 /* BT.1120 */ - -/* - * D V B T T I M I N G S - */ - -/* BT.656/BT.1120 timing data */ -struct v4l2_bt_timings { - __u32 width; /* width in pixels */ - __u32 height; /* height in lines */ - __u32 interlaced; /* Interlaced or progressive */ - __u32 polarities; /* Positive or negative polarity */ - __u64 pixelclock; /* Pixel clock in HZ. Ex. 74.25MHz->74250000 */ - __u32 hfrontporch; /* Horizpontal front porch in pixels */ - __u32 hsync; /* Horizontal Sync length in pixels */ - __u32 hbackporch; /* Horizontal back porch in pixels */ - __u32 vfrontporch; /* Vertical front porch in pixels */ - __u32 vsync; /* Vertical Sync length in lines */ - __u32 vbackporch; /* Vertical back porch in lines */ - __u32 il_vfrontporch; /* Vertical front porch for bottom field of - * interlaced field formats - */ - __u32 il_vsync; /* Vertical sync length for bottom field of - * interlaced field formats - */ - __u32 il_vbackporch; /* Vertical back porch for bottom field of - * interlaced field formats - */ - __u32 reserved[16]; -} __attribute__ ((packed)); - -/* Interlaced or progressive format */ -#define V4L2_DV_PROGRESSIVE 0 -#define V4L2_DV_INTERLACED 1 - -/* Polarities. If bit is not set, it is assumed to be negative polarity */ -#define V4L2_DV_VSYNC_POS_POL 0x00000001 -#define V4L2_DV_HSYNC_POS_POL 0x00000002 - - -/* DV timings */ -struct v4l2_dv_timings { - __u32 type; - union { - struct v4l2_bt_timings bt; - __u32 reserved[32]; - }; -} __attribute__ ((packed)); - -/* Values for the type field */ -#define V4L2_DV_BT_656_1120 0 /* BT.656/1120 timing type */ - -/* - * V I D E O I N P U T S - */ -struct v4l2_input { - __u32 index; /* Which input */ - __u8 name[32]; /* Label */ - __u32 type; /* Type of input */ - __u32 audioset; /* Associated audios (bitfield) */ - __u32 tuner; /* Associated tuner */ - v4l2_std_id std; - __u32 status; - __u32 capabilities; - __u32 reserved[3]; -}; - -/* Values for the 'type' field */ -#define V4L2_INPUT_TYPE_TUNER 1 -#define V4L2_INPUT_TYPE_CAMERA 2 - -/* field 'status' - general */ -#define V4L2_IN_ST_NO_POWER 0x00000001 /* Attached device is off */ -#define V4L2_IN_ST_NO_SIGNAL 0x00000002 -#define V4L2_IN_ST_NO_COLOR 0x00000004 - -/* field 'status' - sensor orientation */ -/* If sensor is mounted upside down set both bits */ -#define V4L2_IN_ST_HFLIP 0x00000010 /* Frames are flipped horizontally */ -#define V4L2_IN_ST_VFLIP 0x00000020 /* Frames are flipped vertically */ - -/* field 'status' - analog */ -#define V4L2_IN_ST_NO_H_LOCK 0x00000100 /* No horizontal sync lock */ -#define V4L2_IN_ST_COLOR_KILL 0x00000200 /* Color killer is active */ - -/* field 'status' - digital */ -#define V4L2_IN_ST_NO_SYNC 0x00010000 /* No synchronization lock */ -#define V4L2_IN_ST_NO_EQU 0x00020000 /* No equalizer lock */ -#define V4L2_IN_ST_NO_CARRIER 0x00040000 /* Carrier recovery failed */ - -/* field 'status' - VCR and set-top box */ -#define V4L2_IN_ST_MACROVISION 0x01000000 /* Macrovision detected */ -#define V4L2_IN_ST_NO_ACCESS 0x02000000 /* Conditional access denied */ -#define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */ - -/* capabilities flags */ -#define V4L2_IN_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ -#define V4L2_IN_CAP_CUSTOM_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ -#define V4L2_IN_CAP_STD 0x00000004 /* Supports S_STD */ - -/* - * V I D E O O U T P U T S - */ -struct v4l2_output { - __u32 index; /* Which output */ - __u8 name[32]; /* Label */ - __u32 type; /* Type of output */ - __u32 audioset; /* Associated audios (bitfield) */ - __u32 modulator; /* Associated modulator */ - v4l2_std_id std; - __u32 capabilities; - __u32 reserved[3]; -}; -/* Values for the 'type' field */ -#define V4L2_OUTPUT_TYPE_MODULATOR 1 -#define V4L2_OUTPUT_TYPE_ANALOG 2 -#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 - -/* capabilities flags */ -#define V4L2_OUT_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ -#define V4L2_OUT_CAP_CUSTOM_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ -#define V4L2_OUT_CAP_STD 0x00000004 /* Supports S_STD */ - -/* - * C O N T R O L S - */ -struct v4l2_control { - __u32 id; - __s32 value; -}; - -struct v4l2_ext_control { - __u32 id; - __u32 size; - __u32 reserved2[1]; - union { - __s32 value; - __s64 value64; - char *string; - }; -} __attribute__ ((packed)); - -struct v4l2_ext_controls { - __u32 ctrl_class; - __u32 count; - __u32 error_idx; - __u32 reserved[2]; - struct v4l2_ext_control *controls; -}; - -/* Values for ctrl_class field */ -#define V4L2_CTRL_CLASS_USER 0x00980000 /* Old-style 'user' controls */ -#define V4L2_CTRL_CLASS_MPEG 0x00990000 /* MPEG-compression controls */ -#define V4L2_CTRL_CLASS_CAMERA 0x009a0000 /* Camera class controls */ -#define V4L2_CTRL_CLASS_FM_TX 0x009b0000 /* FM Modulator control class */ - -#define V4L2_CTRL_ID_MASK (0x0fffffff) -#define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL) -#define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000) - -enum v4l2_ctrl_type { - V4L2_CTRL_TYPE_INTEGER = 1, - V4L2_CTRL_TYPE_BOOLEAN = 2, - V4L2_CTRL_TYPE_MENU = 3, - V4L2_CTRL_TYPE_BUTTON = 4, - V4L2_CTRL_TYPE_INTEGER64 = 5, - V4L2_CTRL_TYPE_CTRL_CLASS = 6, - V4L2_CTRL_TYPE_STRING = 7, -}; - -/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */ -struct v4l2_queryctrl { - __u32 id; - enum v4l2_ctrl_type type; - __u8 name[32]; /* Whatever */ - __s32 minimum; /* Note signedness */ - __s32 maximum; - __s32 step; - __s32 default_value; - __u32 flags; - __u32 reserved[2]; -}; - -/* Used in the VIDIOC_QUERYMENU ioctl for querying menu items */ -struct v4l2_querymenu { - __u32 id; - __u32 index; - __u8 name[32]; /* Whatever */ - __u32 reserved; -}; - -/* Control flags */ -#define V4L2_CTRL_FLAG_DISABLED 0x0001 -#define V4L2_CTRL_FLAG_GRABBED 0x0002 -#define V4L2_CTRL_FLAG_READ_ONLY 0x0004 -#define V4L2_CTRL_FLAG_UPDATE 0x0008 -#define V4L2_CTRL_FLAG_INACTIVE 0x0010 -#define V4L2_CTRL_FLAG_SLIDER 0x0020 -#define V4L2_CTRL_FLAG_WRITE_ONLY 0x0040 - -/* Query flag, to be ORed with the control ID */ -#define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000 - -/* User-class control IDs defined by V4L2 */ -#define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900) -#define V4L2_CID_USER_BASE V4L2_CID_BASE -/* IDs reserved for driver specific controls */ -#define V4L2_CID_PRIVATE_BASE 0x08000000 - -#define V4L2_CID_USER_CLASS (V4L2_CTRL_CLASS_USER | 1) -#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0) -#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1) -#define V4L2_CID_SATURATION (V4L2_CID_BASE+2) -#define V4L2_CID_HUE (V4L2_CID_BASE+3) -#define V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5) -#define V4L2_CID_AUDIO_BALANCE (V4L2_CID_BASE+6) -#define V4L2_CID_AUDIO_BASS (V4L2_CID_BASE+7) -#define V4L2_CID_AUDIO_TREBLE (V4L2_CID_BASE+8) -#define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9) -#define V4L2_CID_AUDIO_LOUDNESS (V4L2_CID_BASE+10) -#define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11) /* Deprecated */ -#define V4L2_CID_AUTO_WHITE_BALANCE (V4L2_CID_BASE+12) -#define V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13) -#define V4L2_CID_RED_BALANCE (V4L2_CID_BASE+14) -#define V4L2_CID_BLUE_BALANCE (V4L2_CID_BASE+15) -#define V4L2_CID_GAMMA (V4L2_CID_BASE+16) -#define V4L2_CID_WHITENESS (V4L2_CID_GAMMA) /* Deprecated */ -#define V4L2_CID_EXPOSURE (V4L2_CID_BASE+17) -#define V4L2_CID_AUTOGAIN (V4L2_CID_BASE+18) -#define V4L2_CID_GAIN (V4L2_CID_BASE+19) -#define V4L2_CID_HFLIP (V4L2_CID_BASE+20) -#define V4L2_CID_VFLIP (V4L2_CID_BASE+21) - -/* Deprecated; use V4L2_CID_PAN_RESET and V4L2_CID_TILT_RESET */ -#define V4L2_CID_HCENTER (V4L2_CID_BASE+22) -#define V4L2_CID_VCENTER (V4L2_CID_BASE+23) - -#define V4L2_CID_POWER_LINE_FREQUENCY (V4L2_CID_BASE+24) -enum v4l2_power_line_frequency { - V4L2_CID_POWER_LINE_FREQUENCY_DISABLED = 0, - V4L2_CID_POWER_LINE_FREQUENCY_50HZ = 1, - V4L2_CID_POWER_LINE_FREQUENCY_60HZ = 2, -}; -#define V4L2_CID_HUE_AUTO (V4L2_CID_BASE+25) -#define V4L2_CID_WHITE_BALANCE_TEMPERATURE (V4L2_CID_BASE+26) -#define V4L2_CID_SHARPNESS (V4L2_CID_BASE+27) -#define V4L2_CID_BACKLIGHT_COMPENSATION (V4L2_CID_BASE+28) -#define V4L2_CID_CHROMA_AGC (V4L2_CID_BASE+29) -#define V4L2_CID_COLOR_KILLER (V4L2_CID_BASE+30) -#define V4L2_CID_COLORFX (V4L2_CID_BASE+31) -enum v4l2_colorfx { - V4L2_COLORFX_NONE = 0, - V4L2_COLORFX_BW = 1, - V4L2_COLORFX_SEPIA = 2, - V4L2_COLORFX_NEGATIVE = 3, - V4L2_COLORFX_EMBOSS = 4, - V4L2_COLORFX_SKETCH = 5, - V4L2_COLORFX_SKY_BLUE = 6, - V4L2_COLORFX_GRASS_GREEN = 7, - V4L2_COLORFX_SKIN_WHITEN = 8, - V4L2_COLORFX_VIVID = 9, -}; -#define V4L2_CID_AUTOBRIGHTNESS (V4L2_CID_BASE+32) -#define V4L2_CID_BAND_STOP_FILTER (V4L2_CID_BASE+33) - -#define V4L2_CID_ROTATE (V4L2_CID_BASE+34) -#define V4L2_CID_BG_COLOR (V4L2_CID_BASE+35) - -#define V4L2_CID_CHROMA_GAIN (V4L2_CID_BASE+36) - -#define V4L2_CID_ILLUMINATORS_1 (V4L2_CID_BASE+37) -#define V4L2_CID_ILLUMINATORS_2 (V4L2_CID_BASE+38) - -/* last CID + 1 */ -#define V4L2_CID_LASTP1 (V4L2_CID_BASE+39) - -/* MPEG-class control IDs defined by V4L2 */ -#define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900) -#define V4L2_CID_MPEG_CLASS (V4L2_CTRL_CLASS_MPEG | 1) - -/* MPEG streams */ -#define V4L2_CID_MPEG_STREAM_TYPE (V4L2_CID_MPEG_BASE+0) -enum v4l2_mpeg_stream_type { - V4L2_MPEG_STREAM_TYPE_MPEG2_PS = 0, /* MPEG-2 program stream */ - V4L2_MPEG_STREAM_TYPE_MPEG2_TS = 1, /* MPEG-2 transport stream */ - V4L2_MPEG_STREAM_TYPE_MPEG1_SS = 2, /* MPEG-1 system stream */ - V4L2_MPEG_STREAM_TYPE_MPEG2_DVD = 3, /* MPEG-2 DVD-compatible stream */ - V4L2_MPEG_STREAM_TYPE_MPEG1_VCD = 4, /* MPEG-1 VCD-compatible stream */ - V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD = 5, /* MPEG-2 SVCD-compatible stream */ -}; -#define V4L2_CID_MPEG_STREAM_PID_PMT (V4L2_CID_MPEG_BASE+1) -#define V4L2_CID_MPEG_STREAM_PID_AUDIO (V4L2_CID_MPEG_BASE+2) -#define V4L2_CID_MPEG_STREAM_PID_VIDEO (V4L2_CID_MPEG_BASE+3) -#define V4L2_CID_MPEG_STREAM_PID_PCR (V4L2_CID_MPEG_BASE+4) -#define V4L2_CID_MPEG_STREAM_PES_ID_AUDIO (V4L2_CID_MPEG_BASE+5) -#define V4L2_CID_MPEG_STREAM_PES_ID_VIDEO (V4L2_CID_MPEG_BASE+6) -#define V4L2_CID_MPEG_STREAM_VBI_FMT (V4L2_CID_MPEG_BASE+7) -enum v4l2_mpeg_stream_vbi_fmt { - V4L2_MPEG_STREAM_VBI_FMT_NONE = 0, /* No VBI in the MPEG stream */ - V4L2_MPEG_STREAM_VBI_FMT_IVTV = 1, /* VBI in private packets, IVTV format */ -}; - -/* MPEG audio */ -#define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ (V4L2_CID_MPEG_BASE+100) -enum v4l2_mpeg_audio_sampling_freq { - V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 = 0, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 = 1, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000 = 2, -}; -#define V4L2_CID_MPEG_AUDIO_ENCODING (V4L2_CID_MPEG_BASE+101) -enum v4l2_mpeg_audio_encoding { - V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0, - V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1, - V4L2_MPEG_AUDIO_ENCODING_LAYER_3 = 2, - V4L2_MPEG_AUDIO_ENCODING_AAC = 3, - V4L2_MPEG_AUDIO_ENCODING_AC3 = 4, -}; -#define V4L2_CID_MPEG_AUDIO_L1_BITRATE (V4L2_CID_MPEG_BASE+102) -enum v4l2_mpeg_audio_l1_bitrate { - V4L2_MPEG_AUDIO_L1_BITRATE_32K = 0, - V4L2_MPEG_AUDIO_L1_BITRATE_64K = 1, - V4L2_MPEG_AUDIO_L1_BITRATE_96K = 2, - V4L2_MPEG_AUDIO_L1_BITRATE_128K = 3, - V4L2_MPEG_AUDIO_L1_BITRATE_160K = 4, - V4L2_MPEG_AUDIO_L1_BITRATE_192K = 5, - V4L2_MPEG_AUDIO_L1_BITRATE_224K = 6, - V4L2_MPEG_AUDIO_L1_BITRATE_256K = 7, - V4L2_MPEG_AUDIO_L1_BITRATE_288K = 8, - V4L2_MPEG_AUDIO_L1_BITRATE_320K = 9, - V4L2_MPEG_AUDIO_L1_BITRATE_352K = 10, - V4L2_MPEG_AUDIO_L1_BITRATE_384K = 11, - V4L2_MPEG_AUDIO_L1_BITRATE_416K = 12, - V4L2_MPEG_AUDIO_L1_BITRATE_448K = 13, -}; -#define V4L2_CID_MPEG_AUDIO_L2_BITRATE (V4L2_CID_MPEG_BASE+103) -enum v4l2_mpeg_audio_l2_bitrate { - V4L2_MPEG_AUDIO_L2_BITRATE_32K = 0, - V4L2_MPEG_AUDIO_L2_BITRATE_48K = 1, - V4L2_MPEG_AUDIO_L2_BITRATE_56K = 2, - V4L2_MPEG_AUDIO_L2_BITRATE_64K = 3, - V4L2_MPEG_AUDIO_L2_BITRATE_80K = 4, - V4L2_MPEG_AUDIO_L2_BITRATE_96K = 5, - V4L2_MPEG_AUDIO_L2_BITRATE_112K = 6, - V4L2_MPEG_AUDIO_L2_BITRATE_128K = 7, - V4L2_MPEG_AUDIO_L2_BITRATE_160K = 8, - V4L2_MPEG_AUDIO_L2_BITRATE_192K = 9, - V4L2_MPEG_AUDIO_L2_BITRATE_224K = 10, - V4L2_MPEG_AUDIO_L2_BITRATE_256K = 11, - V4L2_MPEG_AUDIO_L2_BITRATE_320K = 12, - V4L2_MPEG_AUDIO_L2_BITRATE_384K = 13, -}; -#define V4L2_CID_MPEG_AUDIO_L3_BITRATE (V4L2_CID_MPEG_BASE+104) -enum v4l2_mpeg_audio_l3_bitrate { - V4L2_MPEG_AUDIO_L3_BITRATE_32K = 0, - V4L2_MPEG_AUDIO_L3_BITRATE_40K = 1, - V4L2_MPEG_AUDIO_L3_BITRATE_48K = 2, - V4L2_MPEG_AUDIO_L3_BITRATE_56K = 3, - V4L2_MPEG_AUDIO_L3_BITRATE_64K = 4, - V4L2_MPEG_AUDIO_L3_BITRATE_80K = 5, - V4L2_MPEG_AUDIO_L3_BITRATE_96K = 6, - V4L2_MPEG_AUDIO_L3_BITRATE_112K = 7, - V4L2_MPEG_AUDIO_L3_BITRATE_128K = 8, - V4L2_MPEG_AUDIO_L3_BITRATE_160K = 9, - V4L2_MPEG_AUDIO_L3_BITRATE_192K = 10, - V4L2_MPEG_AUDIO_L3_BITRATE_224K = 11, - V4L2_MPEG_AUDIO_L3_BITRATE_256K = 12, - V4L2_MPEG_AUDIO_L3_BITRATE_320K = 13, -}; -#define V4L2_CID_MPEG_AUDIO_MODE (V4L2_CID_MPEG_BASE+105) -enum v4l2_mpeg_audio_mode { - V4L2_MPEG_AUDIO_MODE_STEREO = 0, - V4L2_MPEG_AUDIO_MODE_JOINT_STEREO = 1, - V4L2_MPEG_AUDIO_MODE_DUAL = 2, - V4L2_MPEG_AUDIO_MODE_MONO = 3, -}; -#define V4L2_CID_MPEG_AUDIO_MODE_EXTENSION (V4L2_CID_MPEG_BASE+106) -enum v4l2_mpeg_audio_mode_extension { - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4 = 0, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8 = 1, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12 = 2, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16 = 3, -}; -#define V4L2_CID_MPEG_AUDIO_EMPHASIS (V4L2_CID_MPEG_BASE+107) -enum v4l2_mpeg_audio_emphasis { - V4L2_MPEG_AUDIO_EMPHASIS_NONE = 0, - V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS = 1, - V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17 = 2, -}; -#define V4L2_CID_MPEG_AUDIO_CRC (V4L2_CID_MPEG_BASE+108) -enum v4l2_mpeg_audio_crc { - V4L2_MPEG_AUDIO_CRC_NONE = 0, - V4L2_MPEG_AUDIO_CRC_CRC16 = 1, -}; -#define V4L2_CID_MPEG_AUDIO_MUTE (V4L2_CID_MPEG_BASE+109) -#define V4L2_CID_MPEG_AUDIO_AAC_BITRATE (V4L2_CID_MPEG_BASE+110) -#define V4L2_CID_MPEG_AUDIO_AC3_BITRATE (V4L2_CID_MPEG_BASE+111) -enum v4l2_mpeg_audio_ac3_bitrate { - V4L2_MPEG_AUDIO_AC3_BITRATE_32K = 0, - V4L2_MPEG_AUDIO_AC3_BITRATE_40K = 1, - V4L2_MPEG_AUDIO_AC3_BITRATE_48K = 2, - V4L2_MPEG_AUDIO_AC3_BITRATE_56K = 3, - V4L2_MPEG_AUDIO_AC3_BITRATE_64K = 4, - V4L2_MPEG_AUDIO_AC3_BITRATE_80K = 5, - V4L2_MPEG_AUDIO_AC3_BITRATE_96K = 6, - V4L2_MPEG_AUDIO_AC3_BITRATE_112K = 7, - V4L2_MPEG_AUDIO_AC3_BITRATE_128K = 8, - V4L2_MPEG_AUDIO_AC3_BITRATE_160K = 9, - V4L2_MPEG_AUDIO_AC3_BITRATE_192K = 10, - V4L2_MPEG_AUDIO_AC3_BITRATE_224K = 11, - V4L2_MPEG_AUDIO_AC3_BITRATE_256K = 12, - V4L2_MPEG_AUDIO_AC3_BITRATE_320K = 13, - V4L2_MPEG_AUDIO_AC3_BITRATE_384K = 14, - V4L2_MPEG_AUDIO_AC3_BITRATE_448K = 15, - V4L2_MPEG_AUDIO_AC3_BITRATE_512K = 16, - V4L2_MPEG_AUDIO_AC3_BITRATE_576K = 17, - V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18, -}; - -/* MPEG video */ -#define V4L2_CID_MPEG_VIDEO_ENCODING (V4L2_CID_MPEG_BASE+200) -enum v4l2_mpeg_video_encoding { - V4L2_MPEG_VIDEO_ENCODING_MPEG_1 = 0, - V4L2_MPEG_VIDEO_ENCODING_MPEG_2 = 1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC = 2, -}; -#define V4L2_CID_MPEG_VIDEO_ASPECT (V4L2_CID_MPEG_BASE+201) -enum v4l2_mpeg_video_aspect { - V4L2_MPEG_VIDEO_ASPECT_1x1 = 0, - V4L2_MPEG_VIDEO_ASPECT_4x3 = 1, - V4L2_MPEG_VIDEO_ASPECT_16x9 = 2, - V4L2_MPEG_VIDEO_ASPECT_221x100 = 3, -}; -#define V4L2_CID_MPEG_VIDEO_B_FRAMES (V4L2_CID_MPEG_BASE+202) -#define V4L2_CID_MPEG_VIDEO_GOP_SIZE (V4L2_CID_MPEG_BASE+203) -#define V4L2_CID_MPEG_VIDEO_GOP_CLOSURE (V4L2_CID_MPEG_BASE+204) -#define V4L2_CID_MPEG_VIDEO_PULLDOWN (V4L2_CID_MPEG_BASE+205) -#define V4L2_CID_MPEG_VIDEO_BITRATE_MODE (V4L2_CID_MPEG_BASE+206) -enum v4l2_mpeg_video_bitrate_mode { - V4L2_MPEG_VIDEO_BITRATE_MODE_VBR = 0, - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR = 1, -}; -#define V4L2_CID_MPEG_VIDEO_BITRATE (V4L2_CID_MPEG_BASE+207) -#define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK (V4L2_CID_MPEG_BASE+208) -#define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209) -#define V4L2_CID_MPEG_VIDEO_MUTE (V4L2_CID_MPEG_BASE+210) -#define V4L2_CID_MPEG_VIDEO_MUTE_YUV (V4L2_CID_MPEG_BASE+211) - -/* MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */ -#define V4L2_CID_MPEG_CX2341X_BASE (V4L2_CTRL_CLASS_MPEG | 0x1000) -#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+0) -enum v4l2_mpeg_cx2341x_video_spatial_filter_mode { - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL = 0, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO = 1, -}; -#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER (V4L2_CID_MPEG_CX2341X_BASE+1) -#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+2) -enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type { - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF = 0, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR = 1, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT = 2, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE = 3, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE = 4, -}; -#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+3) -enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type { - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF = 0, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR = 1, -}; -#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+4) -enum v4l2_mpeg_cx2341x_video_temporal_filter_mode { - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL = 0, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO = 1, -}; -#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER (V4L2_CID_MPEG_CX2341X_BASE+5) -#define V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+6) -enum v4l2_mpeg_cx2341x_video_median_filter_type { - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF = 0, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR = 1, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT = 2, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT = 3, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG = 4, -}; -#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+7) -#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+8) -#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+9) -#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+10) -#define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS (V4L2_CID_MPEG_CX2341X_BASE+11) - -/* Camera class control IDs */ -#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900) -#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1) - -#define V4L2_CID_EXPOSURE_AUTO (V4L2_CID_CAMERA_CLASS_BASE+1) -enum v4l2_exposure_auto_type { - V4L2_EXPOSURE_AUTO = 0, - V4L2_EXPOSURE_MANUAL = 1, - V4L2_EXPOSURE_SHUTTER_PRIORITY = 2, - V4L2_EXPOSURE_APERTURE_PRIORITY = 3 -}; -#define V4L2_CID_EXPOSURE_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+2) -#define V4L2_CID_EXPOSURE_AUTO_PRIORITY (V4L2_CID_CAMERA_CLASS_BASE+3) - -#define V4L2_CID_PAN_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+4) -#define V4L2_CID_TILT_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+5) -#define V4L2_CID_PAN_RESET (V4L2_CID_CAMERA_CLASS_BASE+6) -#define V4L2_CID_TILT_RESET (V4L2_CID_CAMERA_CLASS_BASE+7) - -#define V4L2_CID_PAN_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+8) -#define V4L2_CID_TILT_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+9) - -#define V4L2_CID_FOCUS_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+10) -#define V4L2_CID_FOCUS_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+11) -#define V4L2_CID_FOCUS_AUTO (V4L2_CID_CAMERA_CLASS_BASE+12) - -#define V4L2_CID_ZOOM_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+13) -#define V4L2_CID_ZOOM_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+14) -#define V4L2_CID_ZOOM_CONTINUOUS (V4L2_CID_CAMERA_CLASS_BASE+15) - -#define V4L2_CID_PRIVACY (V4L2_CID_CAMERA_CLASS_BASE+16) - -#define V4L2_CID_IRIS_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+17) -#define V4L2_CID_IRIS_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+18) - -/* FM Modulator class control IDs */ -#define V4L2_CID_FM_TX_CLASS_BASE (V4L2_CTRL_CLASS_FM_TX | 0x900) -#define V4L2_CID_FM_TX_CLASS (V4L2_CTRL_CLASS_FM_TX | 1) - -#define V4L2_CID_RDS_TX_DEVIATION (V4L2_CID_FM_TX_CLASS_BASE + 1) -#define V4L2_CID_RDS_TX_PI (V4L2_CID_FM_TX_CLASS_BASE + 2) -#define V4L2_CID_RDS_TX_PTY (V4L2_CID_FM_TX_CLASS_BASE + 3) -#define V4L2_CID_RDS_TX_PS_NAME (V4L2_CID_FM_TX_CLASS_BASE + 5) -#define V4L2_CID_RDS_TX_RADIO_TEXT (V4L2_CID_FM_TX_CLASS_BASE + 6) - -#define V4L2_CID_AUDIO_LIMITER_ENABLED (V4L2_CID_FM_TX_CLASS_BASE + 64) -#define V4L2_CID_AUDIO_LIMITER_RELEASE_TIME (V4L2_CID_FM_TX_CLASS_BASE + 65) -#define V4L2_CID_AUDIO_LIMITER_DEVIATION (V4L2_CID_FM_TX_CLASS_BASE + 66) - -#define V4L2_CID_AUDIO_COMPRESSION_ENABLED (V4L2_CID_FM_TX_CLASS_BASE + 80) -#define V4L2_CID_AUDIO_COMPRESSION_GAIN (V4L2_CID_FM_TX_CLASS_BASE + 81) -#define V4L2_CID_AUDIO_COMPRESSION_THRESHOLD (V4L2_CID_FM_TX_CLASS_BASE + 82) -#define V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME (V4L2_CID_FM_TX_CLASS_BASE + 83) -#define V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME (V4L2_CID_FM_TX_CLASS_BASE + 84) - -#define V4L2_CID_PILOT_TONE_ENABLED (V4L2_CID_FM_TX_CLASS_BASE + 96) -#define V4L2_CID_PILOT_TONE_DEVIATION (V4L2_CID_FM_TX_CLASS_BASE + 97) -#define V4L2_CID_PILOT_TONE_FREQUENCY (V4L2_CID_FM_TX_CLASS_BASE + 98) - -#define V4L2_CID_TUNE_PREEMPHASIS (V4L2_CID_FM_TX_CLASS_BASE + 112) -enum v4l2_preemphasis { - V4L2_PREEMPHASIS_DISABLED = 0, - V4L2_PREEMPHASIS_50_uS = 1, - V4L2_PREEMPHASIS_75_uS = 2, -}; -#define V4L2_CID_TUNE_POWER_LEVEL (V4L2_CID_FM_TX_CLASS_BASE + 113) -#define V4L2_CID_TUNE_ANTENNA_CAPACITOR (V4L2_CID_FM_TX_CLASS_BASE + 114) - -/* - * T U N I N G - */ -struct v4l2_tuner { - __u32 index; - __u8 name[32]; - enum v4l2_tuner_type type; - __u32 capability; - __u32 rangelow; - __u32 rangehigh; - __u32 rxsubchans; - __u32 audmode; - __s32 signal; - __s32 afc; - __u32 reserved[4]; -}; - -struct v4l2_modulator { - __u32 index; - __u8 name[32]; - __u32 capability; - __u32 rangelow; - __u32 rangehigh; - __u32 txsubchans; - __u32 reserved[4]; -}; - -/* Flags for the 'capability' field */ -#define V4L2_TUNER_CAP_LOW 0x0001 -#define V4L2_TUNER_CAP_NORM 0x0002 -#define V4L2_TUNER_CAP_STEREO 0x0010 -#define V4L2_TUNER_CAP_LANG2 0x0020 -#define V4L2_TUNER_CAP_SAP 0x0020 -#define V4L2_TUNER_CAP_LANG1 0x0040 -#define V4L2_TUNER_CAP_RDS 0x0080 -#define V4L2_TUNER_CAP_RDS_BLOCK_IO 0x0100 -#define V4L2_TUNER_CAP_RDS_CONTROLS 0x0200 - -/* Flags for the 'rxsubchans' field */ -#define V4L2_TUNER_SUB_MONO 0x0001 -#define V4L2_TUNER_SUB_STEREO 0x0002 -#define V4L2_TUNER_SUB_LANG2 0x0004 -#define V4L2_TUNER_SUB_SAP 0x0004 -#define V4L2_TUNER_SUB_LANG1 0x0008 -#define V4L2_TUNER_SUB_RDS 0x0010 - -/* Values for the 'audmode' field */ -#define V4L2_TUNER_MODE_MONO 0x0000 -#define V4L2_TUNER_MODE_STEREO 0x0001 -#define V4L2_TUNER_MODE_LANG2 0x0002 -#define V4L2_TUNER_MODE_SAP 0x0002 -#define V4L2_TUNER_MODE_LANG1 0x0003 -#define V4L2_TUNER_MODE_LANG1_LANG2 0x0004 - -struct v4l2_frequency { - __u32 tuner; - enum v4l2_tuner_type type; - __u32 frequency; - __u32 reserved[8]; -}; - -struct v4l2_hw_freq_seek { - __u32 tuner; - enum v4l2_tuner_type type; - __u32 seek_upward; - __u32 wrap_around; - __u32 spacing; - __u32 reserved[7]; -}; - -/* - * R D S - */ - -struct v4l2_rds_data { - __u8 lsb; - __u8 msb; - __u8 block; -} __attribute__ ((packed)); - -#define V4L2_RDS_BLOCK_MSK 0x7 -#define V4L2_RDS_BLOCK_A 0 -#define V4L2_RDS_BLOCK_B 1 -#define V4L2_RDS_BLOCK_C 2 -#define V4L2_RDS_BLOCK_D 3 -#define V4L2_RDS_BLOCK_C_ALT 4 -#define V4L2_RDS_BLOCK_INVALID 7 - -#define V4L2_RDS_BLOCK_CORRECTED 0x40 -#define V4L2_RDS_BLOCK_ERROR 0x80 - -/* - * A U D I O - */ -struct v4l2_audio { - __u32 index; - __u8 name[32]; - __u32 capability; - __u32 mode; - __u32 reserved[2]; -}; - -/* Flags for the 'capability' field */ -#define V4L2_AUDCAP_STEREO 0x00001 -#define V4L2_AUDCAP_AVL 0x00002 - -/* Flags for the 'mode' field */ -#define V4L2_AUDMODE_AVL 0x00001 - -struct v4l2_audioout { - __u32 index; - __u8 name[32]; - __u32 capability; - __u32 mode; - __u32 reserved[2]; -}; - -/* - * M P E G S E R V I C E S - * - * NOTE: EXPERIMENTAL API - */ -#if 1 -#define V4L2_ENC_IDX_FRAME_I (0) -#define V4L2_ENC_IDX_FRAME_P (1) -#define V4L2_ENC_IDX_FRAME_B (2) -#define V4L2_ENC_IDX_FRAME_MASK (0xf) - -struct v4l2_enc_idx_entry { - __u64 offset; - __u64 pts; - __u32 length; - __u32 flags; - __u32 reserved[2]; -}; - -#define V4L2_ENC_IDX_ENTRIES (64) -struct v4l2_enc_idx { - __u32 entries; - __u32 entries_cap; - __u32 reserved[4]; - struct v4l2_enc_idx_entry entry[V4L2_ENC_IDX_ENTRIES]; -}; - - -#define V4L2_ENC_CMD_START (0) -#define V4L2_ENC_CMD_STOP (1) -#define V4L2_ENC_CMD_PAUSE (2) -#define V4L2_ENC_CMD_RESUME (3) - -/* Flags for V4L2_ENC_CMD_STOP */ -#define V4L2_ENC_CMD_STOP_AT_GOP_END (1 << 0) - -struct v4l2_encoder_cmd { - __u32 cmd; - __u32 flags; - union { - struct { - __u32 data[8]; - } raw; - }; -}; - -#endif - - -/* - * D A T A S E R V I C E S ( V B I ) - * - * Data services API by Michael Schimek - */ - -/* Raw VBI */ -struct v4l2_vbi_format { - __u32 sampling_rate; /* in 1 Hz */ - __u32 offset; - __u32 samples_per_line; - __u32 sample_format; /* V4L2_PIX_FMT_* */ - __s32 start[2]; - __u32 count[2]; - __u32 flags; /* V4L2_VBI_* */ - __u32 reserved[2]; /* must be zero */ -}; - -/* VBI flags */ -#define V4L2_VBI_UNSYNC (1 << 0) -#define V4L2_VBI_INTERLACED (1 << 1) - -/* Sliced VBI - * - * This implements is a proposal V4L2 API to allow SLICED VBI - * required for some hardware encoders. It should change without - * notice in the definitive implementation. - */ - -struct v4l2_sliced_vbi_format { - __u16 service_set; - /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field - service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field - (equals frame lines 313-336 for 625 line video - standards, 263-286 for 525 line standards) */ - __u16 service_lines[2][24]; - __u32 io_size; - __u32 reserved[2]; /* must be zero */ -}; - -/* Teletext World System Teletext - (WST), defined on ITU-R BT.653-2 */ -#define V4L2_SLICED_TELETEXT_B (0x0001) -/* Video Program System, defined on ETS 300 231*/ -#define V4L2_SLICED_VPS (0x0400) -/* Closed Caption, defined on EIA-608 */ -#define V4L2_SLICED_CAPTION_525 (0x1000) -/* Wide Screen System, defined on ITU-R BT1119.1 */ -#define V4L2_SLICED_WSS_625 (0x4000) - -#define V4L2_SLICED_VBI_525 (V4L2_SLICED_CAPTION_525) -#define V4L2_SLICED_VBI_625 (V4L2_SLICED_TELETEXT_B | V4L2_SLICED_VPS | V4L2_SLICED_WSS_625) - -struct v4l2_sliced_vbi_cap { - __u16 service_set; - /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field - service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field - (equals frame lines 313-336 for 625 line video - standards, 263-286 for 525 line standards) */ - __u16 service_lines[2][24]; - enum v4l2_buf_type type; - __u32 reserved[3]; /* must be 0 */ -}; - -struct v4l2_sliced_vbi_data { - __u32 id; - __u32 field; /* 0: first field, 1: second field */ - __u32 line; /* 1-23 */ - __u32 reserved; /* must be 0 */ - __u8 data[48]; -}; - -/* - * Sliced VBI data inserted into MPEG Streams - */ - -/* - * V4L2_MPEG_STREAM_VBI_FMT_IVTV: - * - * Structure of payload contained in an MPEG 2 Private Stream 1 PES Packet in an - * MPEG-2 Program Pack that contains V4L2_MPEG_STREAM_VBI_FMT_IVTV Sliced VBI - * data - * - * Note, the MPEG-2 Program Pack and Private Stream 1 PES packet header - * definitions are not included here. See the MPEG-2 specifications for details - * on these headers. - */ - -/* Line type IDs */ -#define V4L2_MPEG_VBI_IVTV_TELETEXT_B (1) -#define V4L2_MPEG_VBI_IVTV_CAPTION_525 (4) -#define V4L2_MPEG_VBI_IVTV_WSS_625 (5) -#define V4L2_MPEG_VBI_IVTV_VPS (7) - -struct v4l2_mpeg_vbi_itv0_line { - __u8 id; /* One of V4L2_MPEG_VBI_IVTV_* above */ - __u8 data[42]; /* Sliced VBI data for the line */ -} __attribute__ ((packed)); - -struct v4l2_mpeg_vbi_itv0 { - __le32 linemask[2]; /* Bitmasks of VBI service lines present */ - struct v4l2_mpeg_vbi_itv0_line line[35]; -} __attribute__ ((packed)); - -struct v4l2_mpeg_vbi_ITV0 { - struct v4l2_mpeg_vbi_itv0_line line[36]; -} __attribute__ ((packed)); - -#define V4L2_MPEG_VBI_IVTV_MAGIC0 "itv0" -#define V4L2_MPEG_VBI_IVTV_MAGIC1 "ITV0" - -struct v4l2_mpeg_vbi_fmt_ivtv { - __u8 magic[4]; - union { - struct v4l2_mpeg_vbi_itv0 itv0; - struct v4l2_mpeg_vbi_ITV0 ITV0; - }; -} __attribute__ ((packed)); - -/* - * A G G R E G A T E S T R U C T U R E S - */ - -/** - * struct v4l2_plane_pix_format - additional, per-plane format definition - * @sizeimage: maximum size in bytes required for data, for which - * this plane will be used - * @bytesperline: distance in bytes between the leftmost pixels in two - * adjacent lines - */ -struct v4l2_plane_pix_format { - __u32 sizeimage; - __u16 bytesperline; - __u16 reserved[7]; -} __attribute__ ((packed)); - -/** - * struct v4l2_pix_format_mplane - multiplanar format definition - * @width: image width in pixels - * @height: image height in pixels - * @pixelformat: little endian four character code (fourcc) - * @field: field order (for interlaced video) - * @colorspace: supplemental to pixelformat - * @plane_fmt: per-plane information - * @num_planes: number of planes for this format - */ -struct v4l2_pix_format_mplane { - __u32 width; - __u32 height; - __u32 pixelformat; - enum v4l2_field field; - enum v4l2_colorspace colorspace; - - struct v4l2_plane_pix_format plane_fmt[VIDEO_MAX_PLANES]; - __u8 num_planes; - __u8 reserved[11]; -} __attribute__ ((packed)); - -/** - * struct v4l2_format - stream data format - * @type: type of the data stream - * @pix: definition of an image format - * @pix_mp: definition of a multiplanar image format - * @win: definition of an overlaid image - * @vbi: raw VBI capture or output parameters - * @sliced: sliced VBI capture or output parameters - * @raw_data: placeholder for future extensions and custom formats - */ -struct v4l2_format { - enum v4l2_buf_type type; - union { - struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */ - struct v4l2_pix_format_mplane pix_mp; /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */ - struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */ - struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */ - struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */ - __u8 raw_data[200]; /* user-defined */ - } fmt; -}; - -/* Stream type-dependent parameters - */ -struct v4l2_streamparm { - enum v4l2_buf_type type; - union { - struct v4l2_captureparm capture; - struct v4l2_outputparm output; - __u8 raw_data[200]; /* user-defined */ - } parm; -}; - -/* - * E V E N T S - */ - -#define V4L2_EVENT_ALL 0 -#define V4L2_EVENT_VSYNC 1 -#define V4L2_EVENT_EOS 2 -#define V4L2_EVENT_PRIVATE_START 0x08000000 - -/* Payload for V4L2_EVENT_VSYNC */ -struct v4l2_event_vsync { - /* Can be V4L2_FIELD_ANY, _NONE, _TOP or _BOTTOM */ - __u8 field; -} __attribute__ ((packed)); - -struct v4l2_event { - __u32 type; - union { - struct v4l2_event_vsync vsync; - __u8 data[64]; - } u; - __u32 pending; - __u32 sequence; - struct timespec timestamp; - __u32 reserved[9]; -}; - -struct v4l2_event_subscription { - __u32 type; - __u32 reserved[7]; -}; - -/* - * A D V A N C E D D E B U G G I N G - * - * NOTE: EXPERIMENTAL API, NEVER RELY ON THIS IN APPLICATIONS! - * FOR DEBUGGING, TESTING AND INTERNAL USE ONLY! - */ - -/* VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER */ - -#define V4L2_CHIP_MATCH_HOST 0 /* Match against chip ID on host (0 for the host) */ -#define V4L2_CHIP_MATCH_I2C_DRIVER 1 /* Match against I2C driver name */ -#define V4L2_CHIP_MATCH_I2C_ADDR 2 /* Match against I2C 7-bit address */ -#define V4L2_CHIP_MATCH_AC97 3 /* Match against anciliary AC97 chip */ - -struct v4l2_dbg_match { - __u32 type; /* Match type */ - union { /* Match this chip, meaning determined by type */ - __u32 addr; - char name[32]; - }; -} __attribute__ ((packed)); - -struct v4l2_dbg_register { - struct v4l2_dbg_match match; - __u32 size; /* register size in bytes */ - __u64 reg; - __u64 val; -} __attribute__ ((packed)); - -/* VIDIOC_DBG_G_CHIP_IDENT */ -struct v4l2_dbg_chip_ident { - struct v4l2_dbg_match match; - __u32 ident; /* chip identifier as specified in <media/v4l2-chip-ident.h> */ - __u32 revision; /* chip revision, chip specific */ -} __attribute__ ((packed)); - -/* - * I O C T L C O D E S F O R V I D E O D E V I C E S - * - */ -#define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability) -#define VIDIOC_RESERVED _IO('V', 1) -#define VIDIOC_ENUM_FMT _IOWR('V', 2, struct v4l2_fmtdesc) -#define VIDIOC_G_FMT _IOWR('V', 4, struct v4l2_format) -#define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format) -#define VIDIOC_REQBUFS _IOWR('V', 8, struct v4l2_requestbuffers) -#define VIDIOC_QUERYBUF _IOWR('V', 9, struct v4l2_buffer) -#define VIDIOC_G_FBUF _IOR('V', 10, struct v4l2_framebuffer) -#define VIDIOC_S_FBUF _IOW('V', 11, struct v4l2_framebuffer) -#define VIDIOC_OVERLAY _IOW('V', 14, int) -#define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer) -#define VIDIOC_DQBUF _IOWR('V', 17, struct v4l2_buffer) -#define VIDIOC_STREAMON _IOW('V', 18, int) -#define VIDIOC_STREAMOFF _IOW('V', 19, int) -#define VIDIOC_G_PARM _IOWR('V', 21, struct v4l2_streamparm) -#define VIDIOC_S_PARM _IOWR('V', 22, struct v4l2_streamparm) -#define VIDIOC_G_STD _IOR('V', 23, v4l2_std_id) -#define VIDIOC_S_STD _IOW('V', 24, v4l2_std_id) -#define VIDIOC_ENUMSTD _IOWR('V', 25, struct v4l2_standard) -#define VIDIOC_ENUMINPUT _IOWR('V', 26, struct v4l2_input) -#define VIDIOC_G_CTRL _IOWR('V', 27, struct v4l2_control) -#define VIDIOC_S_CTRL _IOWR('V', 28, struct v4l2_control) -#define VIDIOC_G_TUNER _IOWR('V', 29, struct v4l2_tuner) -#define VIDIOC_S_TUNER _IOW('V', 30, struct v4l2_tuner) -#define VIDIOC_G_AUDIO _IOR('V', 33, struct v4l2_audio) -#define VIDIOC_S_AUDIO _IOW('V', 34, struct v4l2_audio) -#define VIDIOC_QUERYCTRL _IOWR('V', 36, struct v4l2_queryctrl) -#define VIDIOC_QUERYMENU _IOWR('V', 37, struct v4l2_querymenu) -#define VIDIOC_G_INPUT _IOR('V', 38, int) -#define VIDIOC_S_INPUT _IOWR('V', 39, int) -#define VIDIOC_G_OUTPUT _IOR('V', 46, int) -#define VIDIOC_S_OUTPUT _IOWR('V', 47, int) -#define VIDIOC_ENUMOUTPUT _IOWR('V', 48, struct v4l2_output) -#define VIDIOC_G_AUDOUT _IOR('V', 49, struct v4l2_audioout) -#define VIDIOC_S_AUDOUT _IOW('V', 50, struct v4l2_audioout) -#define VIDIOC_G_MODULATOR _IOWR('V', 54, struct v4l2_modulator) -#define VIDIOC_S_MODULATOR _IOW('V', 55, struct v4l2_modulator) -#define VIDIOC_G_FREQUENCY _IOWR('V', 56, struct v4l2_frequency) -#define VIDIOC_S_FREQUENCY _IOW('V', 57, struct v4l2_frequency) -#define VIDIOC_CROPCAP _IOWR('V', 58, struct v4l2_cropcap) -#define VIDIOC_G_CROP _IOWR('V', 59, struct v4l2_crop) -#define VIDIOC_S_CROP _IOW('V', 60, struct v4l2_crop) -#define VIDIOC_G_JPEGCOMP _IOR('V', 61, struct v4l2_jpegcompression) -#define VIDIOC_S_JPEGCOMP _IOW('V', 62, struct v4l2_jpegcompression) -#define VIDIOC_QUERYSTD _IOR('V', 63, v4l2_std_id) -#define VIDIOC_TRY_FMT _IOWR('V', 64, struct v4l2_format) -#define VIDIOC_ENUMAUDIO _IOWR('V', 65, struct v4l2_audio) -#define VIDIOC_ENUMAUDOUT _IOWR('V', 66, struct v4l2_audioout) -#define VIDIOC_G_PRIORITY _IOR('V', 67, enum v4l2_priority) -#define VIDIOC_S_PRIORITY _IOW('V', 68, enum v4l2_priority) -#define VIDIOC_G_SLICED_VBI_CAP _IOWR('V', 69, struct v4l2_sliced_vbi_cap) -#define VIDIOC_LOG_STATUS _IO('V', 70) -#define VIDIOC_G_EXT_CTRLS _IOWR('V', 71, struct v4l2_ext_controls) -#define VIDIOC_S_EXT_CTRLS _IOWR('V', 72, struct v4l2_ext_controls) -#define VIDIOC_TRY_EXT_CTRLS _IOWR('V', 73, struct v4l2_ext_controls) -#if 1 -#define VIDIOC_ENUM_FRAMESIZES _IOWR('V', 74, struct v4l2_frmsizeenum) -#define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct v4l2_frmivalenum) -#define VIDIOC_G_ENC_INDEX _IOR('V', 76, struct v4l2_enc_idx) -#define VIDIOC_ENCODER_CMD _IOWR('V', 77, struct v4l2_encoder_cmd) -#define VIDIOC_TRY_ENCODER_CMD _IOWR('V', 78, struct v4l2_encoder_cmd) -#endif - -#if 1 -/* Experimental, meant for debugging, testing and internal use. - Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined. - You must be root to use these ioctls. Never use these in applications! */ -#define VIDIOC_DBG_S_REGISTER _IOW('V', 79, struct v4l2_dbg_register) -#define VIDIOC_DBG_G_REGISTER _IOWR('V', 80, struct v4l2_dbg_register) - -/* Experimental, meant for debugging, testing and internal use. - Never use this ioctl in applications! */ -#define VIDIOC_DBG_G_CHIP_IDENT _IOWR('V', 81, struct v4l2_dbg_chip_ident) -#endif - -#define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) -#define VIDIOC_ENUM_DV_PRESETS _IOWR('V', 83, struct v4l2_dv_enum_preset) -#define VIDIOC_S_DV_PRESET _IOWR('V', 84, struct v4l2_dv_preset) -#define VIDIOC_G_DV_PRESET _IOWR('V', 85, struct v4l2_dv_preset) -#define VIDIOC_QUERY_DV_PRESET _IOR('V', 86, struct v4l2_dv_preset) -#define VIDIOC_S_DV_TIMINGS _IOWR('V', 87, struct v4l2_dv_timings) -#define VIDIOC_G_DV_TIMINGS _IOWR('V', 88, struct v4l2_dv_timings) -#define VIDIOC_DQEVENT _IOR('V', 89, struct v4l2_event) -#define VIDIOC_SUBSCRIBE_EVENT _IOW('V', 90, struct v4l2_event_subscription) -#define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription) - -/* Reminder: when adding new ioctls please add support for them to - drivers/media/video/v4l2-compat-ioctl32.c as well! */ - -#define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */ - -#endif /* __LINUX_VIDEODEV2_H */ - diff --git a/Documentation/DocBook/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/v4l/vidioc-subscribe-event.xml deleted file mode 100644 index 8b501791aa6801e74a4c86f74437b5b0aac61526..0000000000000000000000000000000000000000 --- a/Documentation/DocBook/v4l/vidioc-subscribe-event.xml +++ /dev/null @@ -1,133 +0,0 @@ - - - ioctl VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT - &manvol; - - - - VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT - Subscribe or unsubscribe event - - - - - - int ioctl - int fd - int request - struct v4l2_event_subscription -*argp - - - - - - Arguments - - - - fd - - &fd; - - - - request - - VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT - - - - argp - - - - - - - - - Description - - Subscribe or unsubscribe V4L2 event. Subscribed events are - dequeued by using the &VIDIOC-DQEVENT; ioctl. - - - struct <structname>v4l2_event_subscription</structname> - - &cs-str; - - - __u32 - type - Type of the event. - - - __u32 - reserved[7] - Reserved for future extensions. Drivers and applications - must set the array to zero. - - - -
- - - Event Types - - &cs-def; - - - V4L2_EVENT_ALL - 0 - All events. V4L2_EVENT_ALL is valid only for - VIDIOC_UNSUBSCRIBE_EVENT for unsubscribing all events at once. - - - - V4L2_EVENT_VSYNC - 1 - This event is triggered on the vertical sync. - This event has &v4l2-event-vsync; associated with it. - - - - V4L2_EVENT_EOS - 2 - This event is triggered when the end of a stream is reached. - This is typically used with MPEG decoders to report to the application - when the last of the MPEG stream has been decoded. - - - - V4L2_EVENT_PRIVATE_START - 0x08000000 - Base event number for driver-private events. - - - -
- - - struct <structname>v4l2_event_vsync</structname> - - &cs-str; - - - __u8 - field - The upcoming field. See &v4l2-field;. - - - -
- -
-
- diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware old mode 100644 new mode 100755 index 3348d313fbe08ca68049dc3e3e3e0580b654a5c1..c466f5831f15040912e447b70a9cc196cab9cfb7 --- a/Documentation/dvb/get_dvb_firmware +++ b/Documentation/dvb/get_dvb_firmware @@ -27,7 +27,7 @@ use IO::Handle; "or51211", "or51132_qam", "or51132_vsb", "bluebird", "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718", "af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395", - "lme2510c_s7395_old"); + "lme2510c_s7395_old", "drxk", "drxk_terratec_h5"); # Check args syntax() if (scalar(@ARGV) != 1); @@ -634,6 +634,37 @@ sub lme2510c_s7395_old { $outfile; } +sub drxk { + my $url = "http://l4m-daten.de/files/"; + my $zipfile = "DDTuner.zip"; + my $hash = "f5a37b9a20a3534997997c0b1382a3e5"; + my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); + my $drvfile = "DDTuner.sys"; + my $fwfile = "drxk_a3.mc"; + + checkstandard(); + + wgetfile($zipfile, $url . $zipfile); + verify($zipfile, $hash); + unzip($zipfile, $tmpdir); + extract("$tmpdir/$drvfile", 0x14dd8, 15634, "$fwfile"); + + "$fwfile" +} + +sub drxk_terratec_h5 { + my $url = "http://www.linuxtv.org/downloads/firmware/"; + my $hash = "19000dada8e2741162ccc50cc91fa7f1"; + my $fwfile = "dvb-usb-terratec-h5-drxk.fw"; + + checkstandard(); + + wgetfile($fwfile, $url . $fwfile); + verify($fwfile, $hash); + + "$fwfile" +} + # --------------------------------------------------------------- # Utilities diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index dfd6a9f4a58338ea5cc5d42fede7b826382685dc..ea0bace0124ad7db95b43f3e8f30c872584bc66b 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -527,6 +527,41 @@ Who: Laurent Pinchart ---------------------------- +What: Support for driver specific ioctls in the pwc driver (everything + defined in media/pwc-ioctl.h) +When: 3.3 +Why: This stems from the v4l1 era, with v4l2 everything can be done with + standardized v4l2 API calls +Who: Hans de Goede + +---------------------------- + +What: Driver specific sysfs API in the pwc driver +When: 3.3 +Why: Setting pan/tilt should be done with v4l2 controls, like with other + cams. The button is available as a standard input device +Who: Hans de Goede + +---------------------------- + +What: Driver specific use of pixfmt.priv in the pwc driver +When: 3.3 +Why: The .priv field never was intended for this, setting a framerate is + support using the standardized S_PARM ioctl +Who: Hans de Goede + +---------------------------- + +What: Software emulation of arbritary resolutions in the pwc driver +When: 3.3 +Why: The pwc driver claims to support any resolution between 160x120 + and 640x480, but emulates this by simply drawing a black border + around the image. Userspace can draw its own black border if it + really wants one. +Who: Hans de Goede + +---------------------------- + What: For VIDIOC_S_FREQUENCY the type field must match the device node's type. If not, return -EINVAL. When: 3.2 diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt index 76a2087db20578e587ba2b63f70109939324b3fc..669b5fb03a868c32f2a3e36fc2380727b66d1636 100644 --- a/Documentation/media-framework.txt +++ b/Documentation/media-framework.txt @@ -310,7 +310,7 @@ is non-immutable. The operation must either configure the hardware or store the configuration information to be applied later. Link configuration must not have any side effect on other links. If an enabled -link at a sink pad prevents another link at the same pad from being disabled, +link at a sink pad prevents another link at the same pad from being enabled, the link_setup operation must return -EBUSY and can't implicitly disable the first enabled link. diff --git a/Documentation/video4linux/API.html b/Documentation/video4linux/API.html index d72fd2aa9158d84748d7fb48afc072a2ec27ce27..256f8efa992c27a30c34bcbeca0c9bc3053f9e2e 100644 --- a/Documentation/video4linux/API.html +++ b/Documentation/video4linux/API.html @@ -9,7 +9,7 @@
- V4L original API + V4L original API Obsoleted by V4L2 API diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 index 87c46347bd6362f0f20927646387cb05444536e3..8910449d23a8e355cc1fc86dd400638224166fc4 100644 --- a/Documentation/video4linux/CARDLIST.cx23885 +++ b/Documentation/video4linux/CARDLIST.cx23885 @@ -27,3 +27,5 @@ 26 -> Hauppauge WinTV-HVR1290 [0070:8551] 27 -> Mygica X8558 PRO DMB-TH [14f1:8578] 28 -> LEADTEK WinFast PxTV1200 [107d:6f22] + 29 -> GoTView X5 3D Hybrid [5654:2390] + 30 -> NetUP Dual DVB-T/C-CI RF [1b55:e2e4] diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88 index 42517d9121ded5df58774558eca89721afc8272d..d9c0f119196d0f2ef15dc1f3a70e40fd46e3524b 100644 --- a/Documentation/video4linux/CARDLIST.cx88 +++ b/Documentation/video4linux/CARDLIST.cx88 @@ -84,3 +84,4 @@ 83 -> Prof 7301 DVB-S/S2 [b034:3034] 84 -> Samsung SMT 7020 DVB-S [18ac:dc00,18ac:dccd] 85 -> Twinhan VP-1027 DVB-S [1822:0023] + 86 -> TeVii S464 DVB-S/S2 [d464:9022] diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index 9aae449440dc465c02780d72600f3496670cbc84..4a7b3df6d8bd7695a0cee2417d3d849b43912345 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -74,3 +74,5 @@ 74 -> Actionmaster/LinXcel/Digitus VC211A (em2800) 75 -> Dikom DK300 (em2882) 76 -> KWorld PlusTV 340U or UB435-Q (ATSC) (em2870) [1b80:a340] + 77 -> EM2874 Leadership ISDBT (em2874) + 78 -> PCTV nanoStick T2 290e (em28174) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 6b4c72d8862d294a5ee2cf8d85a4b63c7845cdaf..7efae9bd73eda9445ce6db29c079a20510d53a49 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -182,3 +182,7 @@ 181 -> TechoTrend TT-budget T-3000 [13c2:2804] 182 -> Kworld PCI SBTVD/ISDB-T Full-Seg Hybrid [17de:b136] 183 -> Compro VideoMate Vista M1F [185b:c900] +184 -> Encore ENLTV-FM 3 [1a7f:2108] +185 -> MagicPro ProHDTV Pro2 DMB-TH/Hybrid [17de:d136] +186 -> Beholder BeholdTV 501 [5ace:5010] +187 -> Beholder BeholdTV 503 FM [5ace:5030] diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index e67c1db968544ede6ddf80514b97ad96866f6ff7..6323b7a20719eb309d86ba6b736efb5ee09ee03a 100644 --- a/Documentation/video4linux/CARDLIST.tuner +++ b/Documentation/video4linux/CARDLIST.tuner @@ -78,8 +78,10 @@ tuner=77 - TCL tuner MF02GIP-5N-E tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner tuner=79 - Philips PAL/SECAM multi (FM1216 MK5) tuner=80 - Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough +tuner=81 - Xceive 4000 tuner tuner=81 - Partsnic (Daewoo) PTI-5NF05 tuner=82 - Philips CU1216L tuner=83 - NXP TDA18271 tuner=84 - Sony BTF-Pxn01Z tuner=85 - Philips FQ1236 MK5 +tuner=86 - Tena TNF5337 MFD diff --git a/Documentation/video4linux/CARDLIST.usbvision b/Documentation/video4linux/CARDLIST.usbvision index 0b72d3fee17ef4bb02a8d37c763a5d73fb84f4d0..6fd1af36514233b1aec68fa575538af85d5faf61 100644 --- a/Documentation/video4linux/CARDLIST.usbvision +++ b/Documentation/video4linux/CARDLIST.usbvision @@ -63,3 +63,5 @@ 62 -> Pinnacle PCTV Bungee USB (PAL) FM [2304:0419] 63 -> Hauppauge WinTv-USB [2400:4200] 64 -> Pinnacle Studio PCTV USB (NTSC) FM V3 [2304:0113] + 65 -> Nogatech USB MicroCam NTSC (NV3000N) [0573:3000] + 66 -> Nogatech USB MicroCam PAL (NV3001P) [0573:3001] diff --git a/Documentation/video4linux/README.davinci-vpbe b/Documentation/video4linux/README.davinci-vpbe new file mode 100644 index 0000000000000000000000000000000000000000..7a460b0685bb6cfe8d2f631de9ee7a24d9031401 --- /dev/null +++ b/Documentation/video4linux/README.davinci-vpbe @@ -0,0 +1,93 @@ + + VPBE V4L2 driver design + ====================================================================== + + File partitioning + ----------------- + V4L2 display device driver + drivers/media/video/davinci/vpbe_display.c + drivers/media/video/davinci/vpbe_display.h + + VPBE display controller + drivers/media/video/davinci/vpbe.c + drivers/media/video/davinci/vpbe.h + + VPBE venc sub device driver + drivers/media/video/davinci/vpbe_venc.c + drivers/media/video/davinci/vpbe_venc.h + drivers/media/video/davinci/vpbe_venc_regs.h + + VPBE osd driver + drivers/media/video/davinci/vpbe_osd.c + drivers/media/video/davinci/vpbe_osd.h + drivers/media/video/davinci/vpbe_osd_regs.h + + Functional partitioning + ----------------------- + + Consists of the following (in the same order as the list under file + partitioning):- + + 1. V4L2 display driver + Implements creation of video2 and video3 device nodes and + provides v4l2 device interface to manage VID0 and VID1 layers. + + 2. Display controller + Loads up VENC, OSD and external encoders such as ths8200. It provides + a set of API calls to V4L2 drivers to set the output/standards + in the VENC or external sub devices. It also provides + a device object to access the services from OSD subdevice + using sub device ops. The connection of external encoders to VENC LCD + controller port is done at init time based on default output and standard + selection or at run time when application change the output through + V4L2 IOCTLs. + + When connected to an external encoder, vpbe controller is also responsible + for setting up the interface between VENC and external encoders based on + board specific settings (specified in board-xxx-evm.c). This allows + interfacing external encoders such as ths8200. The setup_if_config() + is implemented for this as well as configure_venc() (part of the next patch) + API to set timings in VENC for a specific display resolution. As of this + patch series, the interconnection and enabling and setting of the external + encoders is not present, and would be a part of the next patch series. + + 3. VENC subdevice module + Responsible for setting outputs provided through internal DACs and also + setting timings at LCD controller port when external encoders are connected + at the port or LCD panel timings required. When external encoder/LCD panel + is connected, the timings for a specific standard/preset is retrieved from + the board specific table and the values are used to set the timings in + venc using non-standard timing mode. + + Support LCD Panel displays using the VENC. For example to support a Logic + PD display, it requires setting up the LCD controller port with a set of + timings for the resolution supported and setting the dot clock. So we could + add the available outputs as a board specific entry (i.e add the "LogicPD" + output name to board-xxx-evm.c). A table of timings for various LCDs + supported can be maintained in the board specific setup file to support + various LCD displays.As of this patch a basic driver is present, and this + support for external encoders and displays forms a part of the next + patch series. + + 4. OSD module + OSD module implements all OSD layer management and hardware specific + features. The VPBE module interacts with the OSD for enabling and + disabling appropriate features of the OSD. + + Current status:- + + A fully functional working version of the V4L2 driver is available. This + driver has been tested with NTSC and PAL standards and buffer streaming. + + Following are TBDs. + + vpbe display controller + - Add support for external encoders. + - add support for selecting external encoder as default at probe time. + + vpbe venc sub device + - add timings for supporting ths8200 + - add support for LogicPD LCD. + + FB drivers + - Add support for fbdev drivers.- Ready and part of subsequent patches. diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt index 881e7f44491b70a6c803fa68f6185cb4f158b87f..9346fc8cbf2b2323e205f1f8669fd626cfc1047a 100644 --- a/Documentation/video4linux/v4l2-controls.txt +++ b/Documentation/video4linux/v4l2-controls.txt @@ -277,16 +277,13 @@ implement g_volatile_ctrl like this: { switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - ctrl->cur.val = read_reg(0x123); + ctrl->val = read_reg(0x123); break; } } -The 'new value' union is not used in g_volatile_ctrl. In general controls -that need to implement g_volatile_ctrl are read-only controls. - -Note that if one or more controls in a control cluster are marked as volatile, -then all the controls in the cluster are seen as volatile. +Note that you use the 'new value' union as well in g_volatile_ctrl. In general +controls that need to implement g_volatile_ctrl are read-only controls. To mark a control as volatile you have to set the is_volatile flag: @@ -453,6 +450,25 @@ In the example above the following are equivalent for the VOLUME case: ctrl == ctrl->cluster[AUDIO_CL_VOLUME] == state->audio_cluster[AUDIO_CL_VOLUME] ctrl->cluster[AUDIO_CL_MUTE] == state->audio_cluster[AUDIO_CL_MUTE] +In practice using cluster arrays like this becomes very tiresome. So instead +the following equivalent method is used: + + struct { + /* audio cluster */ + struct v4l2_ctrl *volume; + struct v4l2_ctrl *mute; + }; + +The anonymous struct is used to clearly 'cluster' these two control pointers, +but it serves no other purpose. The effect is the same as creating an +array with two control pointers. So you can just do: + + state->volume = v4l2_ctrl_new_std(&state->ctrl_handler, ...); + state->mute = v4l2_ctrl_new_std(&state->ctrl_handler, ...); + v4l2_ctrl_cluster(2, &state->volume); + +And in foo_s_ctrl you can use these pointers directly: state->mute->val. + Note that controls in a cluster may be NULL. For example, if for some reason mute was never added (because the hardware doesn't support that particular feature), then mute will be NULL. So in that case we have a @@ -475,6 +491,43 @@ controls, then the 'is_new' flag would be 1 for both controls. The 'is_new' flag is always 1 when called from v4l2_ctrl_handler_setup(). +Handling autogain/gain-type Controls with Auto Clusters +======================================================= + +A common type of control cluster is one that handles 'auto-foo/foo'-type +controls. Typical examples are autogain/gain, autoexposure/exposure, +autowhitebalance/red balance/blue balance. In all cases you have one controls +that determines whether another control is handled automatically by the hardware, +or whether it is under manual control from the user. + +If the cluster is in automatic mode, then the manual controls should be +marked inactive. When the volatile controls are read the g_volatile_ctrl +operation should return the value that the hardware's automatic mode set up +automatically. + +If the cluster is put in manual mode, then the manual controls should become +active again and the is_volatile flag should be ignored (so g_volatile_ctrl is +no longer called while in manual mode). + +Finally the V4L2_CTRL_FLAG_UPDATE should be set for the auto control since +changing that control affects the control flags of the manual controls. + +In order to simplify this a special variation of v4l2_ctrl_cluster was +introduced: + +void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls, + u8 manual_val, bool set_volatile); + +The first two arguments are identical to v4l2_ctrl_cluster. The third argument +tells the framework which value switches the cluster into manual mode. The +last argument will optionally set the is_volatile flag for the non-auto controls. + +The first control of the cluster is assumed to be the 'auto' control. + +Using this function will ensure that you don't need to handle all the complex +flag and volatile handling. + + VIDIOC_LOG_STATUS Support ========================= @@ -636,9 +689,7 @@ button controls are write-only controls. -EINVAL as the spec says. 5) The spec does not mention what should happen when you try to set/get a -control class controls. ivtv currently returns -EINVAL (indicating that the -control ID does not exist) while the framework will return -EACCES, which -makes more sense. +control class controls. The framework will return -EACCES. Proposals for Extensions diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt index cf21f7aae976a903b43b7d12a69855acfef101e0..f8dcabf7852cfa1f26ef5103703083539e14f7ab 100644 --- a/Documentation/video4linux/v4l2-framework.txt +++ b/Documentation/video4linux/v4l2-framework.txt @@ -817,11 +817,7 @@ int my_open(struct file *file) ... - ret = v4l2_fh_init(&my_fh->fh, vfd); - if (ret) { - kfree(my_fh); - return ret; - } + v4l2_fh_init(&my_fh->fh, vfd); ... @@ -844,7 +840,7 @@ int my_release(struct file *file) Below is a short description of the v4l2_fh functions used: -int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev) +void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev) Initialise the file handle. This *MUST* be performed in the driver's v4l2_file_operations->open() handler. @@ -901,14 +897,38 @@ V4L2 events The V4L2 events provide a generic way to pass events to user space. The driver must use v4l2_fh to be able to support V4L2 events. -Useful functions: +Events are defined by a type and an optional ID. The ID may refer to a V4L2 +object such as a control ID. If unused, then the ID is 0. + +When the user subscribes to an event the driver will allocate a number of +kevent structs for that event. So every (type, ID) event tuple will have +its own set of kevent structs. This guarantees that if a driver is generating +lots of events of one type in a short time, then that will not overwrite +events of another type. + +But if you get more events of one type than the number of kevents that were +reserved, then the oldest event will be dropped and the new one added. + +Furthermore, the internal struct v4l2_subscribed_event has merge() and +replace() callbacks which drivers can set. These callbacks are called when +a new event is raised and there is no more room. The replace() callback +allows you to replace the payload of the old event with that of the new event, +merging any relevant data from the old payload into the new payload that +replaces it. It is called when this event type has only one kevent struct +allocated. The merge() callback allows you to merge the oldest event payload +into that of the second-oldest event payload. It is called when there are two +or more kevent structs allocated. -- v4l2_event_alloc() +This way no status information is lost, just the intermediate steps leading +up to that state. - To use events, the driver must allocate events for the file handle. By - calling the function more than once, the driver may assure that at least n - events in total have been allocated. The function may not be called in - atomic context. +A good example of these replace/merge callbacks is in v4l2-event.c: +ctrls_replace() and ctrls_merge() callbacks for the control event. + +Note: these callbacks can be called from interrupt context, so they must be +fast. + +Useful functions: - v4l2_event_queue() @@ -920,7 +940,9 @@ Useful functions: The video_device->ioctl_ops->vidioc_subscribe_event must check the driver is able to produce events with specified event id. Then it calls - v4l2_event_subscribe() to subscribe the event. + v4l2_event_subscribe() to subscribe the event. The last argument is the + size of the event queue for this event. If it is 0, then the framework + will fill in a default value (this depends on the event type). - v4l2_event_unsubscribe() @@ -935,14 +957,8 @@ Useful functions: Returns the number of pending events. Useful when implementing poll. -Drivers do not initialise events directly. The events are initialised -through v4l2_fh_init() if video_device->ioctl_ops->vidioc_subscribe_event is -non-NULL. This *MUST* be performed in the driver's -v4l2_file_operations->open() handler. - Events are delivered to user space through the poll system call. The driver -can use v4l2_fh->events->wait wait_queue_head_t as the argument for -poll_wait(). +can use v4l2_fh->wait (a wait_queue_head_t) as the argument for poll_wait(). There are standard and private events. New standard events must use the smallest available event type. The drivers must allocate their events from @@ -952,5 +968,4 @@ The first event type in the class is reserved for future use, so the first available event type is 'class base + 1'. An example on how the V4L2 events may be used can be found in the OMAP -3 ISP driver available at as of -writing this. +3 ISP driver (drivers/media/video/omap3isp). diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index cc503aa89c5e3685b6cc5901a2329a67c6926d99..5a886cd2c598c408f3e007e01a5f5e2b0ae9ca94 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -418,6 +418,10 @@ static struct regulator_consumer_supply rx51_vmmc1_supply[] = { REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"), }; +static struct regulator_consumer_supply rx51_vaux2_supply[] = { + REGULATOR_SUPPLY("vdds_csib", "omap3isp"), +}; + static struct regulator_consumer_supply rx51_vaux3_supply[] = { REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"), }; @@ -479,6 +483,8 @@ static struct regulator_init_data rx51_vaux2 = { .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS, }, + .num_consumer_supplies = ARRAY_SIZE(rx51_vaux2_supply), + .consumer_supplies = rx51_vaux2_supply, }; /* VAUX3 - adds more power to VIO_18 rail */ diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 837138e369bc162ca46e94327bfbe0e2fde84ea6..9e0856b2f9e9fcc8adb4455267e0ec4964efa56d 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -957,19 +957,16 @@ static struct resource csi2_resources[] = { }, }; -static struct platform_device csi2_device = { - .name = "sh-mobile-csi2", - .id = 0, +static struct sh_mobile_ceu_companion csi2 = { + .id = 0, .num_resources = ARRAY_SIZE(csi2_resources), .resource = csi2_resources, - .dev = { - .platform_data = &csi2_info, - }, + .platform_data = &csi2_info, }; static struct sh_mobile_ceu_info sh_mobile_ceu_info = { .flags = SH_CEU_FLAG_USE_8BIT_BUS, - .csi2_dev = &csi2_device.dev, + .csi2 = &csi2, }; static struct resource ceu_resources[] = { @@ -1013,7 +1010,6 @@ static struct platform_device *ap4evb_devices[] __initdata = { &lcdc1_device, &lcdc_device, &hdmi_device, - &csi2_device, &ceu_device, &ap4evb_camera, &meram_device, diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 5b36b6c5b448714d044fe1eb7fd8c9c2827cd95b..d41c01f83f152f75589cc228a186a6f98da59a5e 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -1192,8 +1192,8 @@ static struct platform_device sh_mmcif_device = { }; -static int mackerel_camera_add(struct soc_camera_link *icl, struct device *dev); -static void mackerel_camera_del(struct soc_camera_link *icl); +static int mackerel_camera_add(struct soc_camera_device *icd); +static void mackerel_camera_del(struct soc_camera_device *icd); static int camera_set_capture(struct soc_camera_platform_info *info, int enable) @@ -1232,16 +1232,15 @@ static void mackerel_camera_release(struct device *dev) soc_camera_platform_release(&camera_device); } -static int mackerel_camera_add(struct soc_camera_link *icl, - struct device *dev) +static int mackerel_camera_add(struct soc_camera_device *icd) { - return soc_camera_platform_add(icl, dev, &camera_device, &camera_link, + return soc_camera_platform_add(icd, &camera_device, &camera_link, mackerel_camera_release, 0); } -static void mackerel_camera_del(struct soc_camera_link *icl) +static void mackerel_camera_del(struct soc_camera_device *icd) { - soc_camera_platform_del(icl, camera_device, &camera_link); + soc_camera_platform_del(icd, camera_device, &camera_link); } static struct sh_mobile_ceu_info sh_mobile_ceu_info = { diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index 1dc924b2f5087ffa9b1bf8ff212644752fe23fd7..d36265758911faced2e4df8f2d13fa1ab30c816b 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c @@ -332,8 +332,8 @@ static int camera_set_capture(struct soc_camera_platform_info *info, return ret; } -static int ap325rxa_camera_add(struct soc_camera_link *icl, struct device *dev); -static void ap325rxa_camera_del(struct soc_camera_link *icl); +static int ap325rxa_camera_add(struct soc_camera_device *icd); +static void ap325rxa_camera_del(struct soc_camera_device *icd); static struct soc_camera_platform_info camera_info = { .format_name = "UYVY", @@ -366,24 +366,23 @@ static void ap325rxa_camera_release(struct device *dev) soc_camera_platform_release(&camera_device); } -static int ap325rxa_camera_add(struct soc_camera_link *icl, - struct device *dev) +static int ap325rxa_camera_add(struct soc_camera_device *icd) { - int ret = soc_camera_platform_add(icl, dev, &camera_device, &camera_link, + int ret = soc_camera_platform_add(icd, &camera_device, &camera_link, ap325rxa_camera_release, 0); if (ret < 0) return ret; ret = camera_probe(); if (ret < 0) - soc_camera_platform_del(icl, camera_device, &camera_link); + soc_camera_platform_del(icd, camera_device, &camera_link); return ret; } -static void ap325rxa_camera_del(struct soc_camera_link *icl) +static void ap325rxa_camera_del(struct soc_camera_device *icd) { - soc_camera_platform_del(icl, camera_device, &camera_link); + soc_camera_platform_del(icd, camera_device, &camera_link); } #endif /* CONFIG_I2C */ diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 6995940b633a92b1197249d9c3f593c15edf644f..9575db429df46648c25007a6de5395ef22e080f8 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -68,7 +68,6 @@ config VIDEO_V4L2_SUBDEV_API config DVB_CORE tristate "DVB for Linux" - depends on NET && INET select CRC32 help DVB core utility functions for device handling, software fallbacks etc. @@ -85,6 +84,19 @@ config DVB_CORE If unsure say N. +config DVB_NET + bool "DVB Network Support" + default (NET && INET) + depends on NET && INET && DVB_CORE + help + This option enables DVB Network Support which is a part of the DVB + standard. It is used, for example, by automatic firmware updates used + on Set-Top-Boxes. It can also be used to access the Internet via the + DVB card, if the network provider supports it. + + You may want to disable the network support on embedded devices. If + unsure say Y. + config VIDEO_MEDIA tristate default (DVB_CORE && (VIDEO_DEV = n)) || (VIDEO_DEV && (DVB_CORE = n)) || (DVB_CORE && VIDEO_DEV) diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig index 22d3ca36370ec63bc7c9725b228603bb1d1fb940..996302ae210e7b1fe9686a6425662d49f83c4dc3 100644 --- a/drivers/media/common/tuners/Kconfig +++ b/drivers/media/common/tuners/Kconfig @@ -23,6 +23,7 @@ config MEDIA_TUNER depends on VIDEO_MEDIA && I2C select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE @@ -152,6 +153,15 @@ config MEDIA_TUNER_XC5000 This device is only used inside a SiP called together with a demodulator for now. +config MEDIA_TUNER_XC4000 + tristate "Xceive XC4000 silicon tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon tuner XC4000 from Xceive. + This device is only used inside a SiP called together with a + demodulator for now. + config MEDIA_TUNER_MXL5005S tristate "MaxLinear MSL5005S silicon tuner" depends on VIDEO_MEDIA && I2C diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile index 2cb4f5327843eba24d9309a839829e0c17454414..20d24fca2cfbae8bea894665b7918bb890748d66 100644 --- a/drivers/media/common/tuners/Makefile +++ b/drivers/media/common/tuners/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o +obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c index afba6dc5e080396eb1aaade3c5d6ef0872251f08..94a603a60842d815d6a5ac2b271ce48b14eca974 100644 --- a/drivers/media/common/tuners/tuner-types.c +++ b/drivers/media/common/tuners/tuner-types.c @@ -1805,6 +1805,10 @@ struct tunertype tuners[] = { .name = "Xceive 5000 tuner", /* see xc5000.c for details */ }, + [TUNER_XC4000] = { /* Xceive 4000 */ + .name = "Xceive 4000 tuner", + /* see xc4000.c for details */ + }, [TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */ .name = "TCL tuner MF02GIP-5N-E", .params = tuner_tcl_mf02gip_5n_params, diff --git a/drivers/media/common/tuners/xc4000.c b/drivers/media/common/tuners/xc4000.c new file mode 100644 index 0000000000000000000000000000000000000000..634f4d9b6c6380678bf879e50293e9254a813e13 --- /dev/null +++ b/drivers/media/common/tuners/xc4000.c @@ -0,0 +1,1691 @@ +/* + * Driver for Xceive XC4000 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2007 Xceive Corporation + * Copyright (c) 2007 Steven Toth + * Copyright (c) 2009 Devin Heitmueller + * Copyright (c) 2009 Davide Ferri + * Copyright (c) 2010 Istvan Varga + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "xc4000.h" +#include "tuner-i2c.h" +#include "tuner-xc2028-types.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off))."); + +static int no_poweroff; +module_param(no_poweroff, int, 0644); +MODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, " + "0 (default): use device-specific default mode)."); + +static int audio_std; +module_param(audio_std, int, 0644); +MODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly " + "needs to know what audio standard is needed for some video standards " + "with audio A2 or NICAM. The valid settings are a sum of:\n" + " 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n" + " 2: use A2 instead of NICAM or BTSC\n" + " 4: use SECAM/K3 instead of K1\n" + " 8: use PAL-D/K audio for SECAM-D/K\n" + "16: use FM radio input 1 instead of input 2\n" + "32: use mono audio (the lower three bits are ignored)"); + +static char firmware_name[30]; +module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); +MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " + "default firmware name."); + +static DEFINE_MUTEX(xc4000_list_mutex); +static LIST_HEAD(hybrid_tuner_instance_list); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_INFO "%s: " fmt, "xc4000", ## arg) + +/* struct for storing firmware table */ +struct firmware_description { + unsigned int type; + v4l2_std_id id; + __u16 int_freq; + unsigned char *ptr; + unsigned int size; +}; + +struct firmware_properties { + unsigned int type; + v4l2_std_id id; + v4l2_std_id std_req; + __u16 int_freq; + unsigned int scode_table; + int scode_nr; +}; + +struct xc4000_priv { + struct tuner_i2c_props i2c_props; + struct list_head hybrid_tuner_instance_list; + struct firmware_description *firm; + int firm_size; + u32 if_khz; + u32 freq_hz; + u32 bandwidth; + u8 video_standard; + u8 rf_mode; + u8 default_pm; + u8 dvb_amplitude; + u8 set_smoothedcvbs; + u8 ignore_i2c_write_errors; + __u16 firm_version; + struct firmware_properties cur_fw; + __u16 hwmodel; + __u16 hwvers; + struct mutex lock; +}; + +#define XC4000_AUDIO_STD_B 1 +#define XC4000_AUDIO_STD_A2 2 +#define XC4000_AUDIO_STD_K3 4 +#define XC4000_AUDIO_STD_L 8 +#define XC4000_AUDIO_STD_INPUT1 16 +#define XC4000_AUDIO_STD_MONO 32 + +#define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw" + +/* Misc Defines */ +#define MAX_TV_STANDARD 24 +#define XC_MAX_I2C_WRITE_LENGTH 64 +#define XC_POWERED_DOWN 0x80000000U + +/* Signal Types */ +#define XC_RF_MODE_AIR 0 +#define XC_RF_MODE_CABLE 1 + +/* Product id */ +#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 +#define XC_PRODUCT_ID_XC4000 0x0FA0 +#define XC_PRODUCT_ID_XC4100 0x1004 + +/* Registers (Write-only) */ +#define XREG_INIT 0x00 +#define XREG_VIDEO_MODE 0x01 +#define XREG_AUDIO_MODE 0x02 +#define XREG_RF_FREQ 0x03 +#define XREG_D_CODE 0x04 +#define XREG_DIRECTSITTING_MODE 0x05 +#define XREG_SEEK_MODE 0x06 +#define XREG_POWER_DOWN 0x08 +#define XREG_SIGNALSOURCE 0x0A +#define XREG_SMOOTHEDCVBS 0x0E +#define XREG_AMPLITUDE 0x10 + +/* Registers (Read-only) */ +#define XREG_ADC_ENV 0x00 +#define XREG_QUALITY 0x01 +#define XREG_FRAME_LINES 0x02 +#define XREG_HSYNC_FREQ 0x03 +#define XREG_LOCK 0x04 +#define XREG_FREQ_ERROR 0x05 +#define XREG_SNR 0x06 +#define XREG_VERSION 0x07 +#define XREG_PRODUCT_ID 0x08 + +/* + Basic firmware description. This will remain with + the driver for documentation purposes. + + This represents an I2C firmware file encoded as a + string of unsigned char. Format is as follows: + + char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB + char[1 ]=len0_LSB -> length of first write transaction + char[2 ]=data0 -> first byte to be sent + char[3 ]=data1 + char[4 ]=data2 + char[ ]=... + char[M ]=dataN -> last byte to be sent + char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB + char[M+2]=len1_LSB -> length of second write transaction + char[M+3]=data0 + char[M+4]=data1 + ... + etc. + + The [len] value should be interpreted as follows: + + len= len_MSB _ len_LSB + len=1111_1111_1111_1111 : End of I2C_SEQUENCE + len=0000_0000_0000_0000 : Reset command: Do hardware reset + len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) + len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms + + For the RESET and WAIT commands, the two following bytes will contain + immediately the length of the following transaction. +*/ + +struct XC_TV_STANDARD { + const char *Name; + u16 audio_mode; + u16 video_mode; + u16 int_freq; +}; + +/* Tuner standards */ +#define XC4000_MN_NTSC_PAL_BTSC 0 +#define XC4000_MN_NTSC_PAL_A2 1 +#define XC4000_MN_NTSC_PAL_EIAJ 2 +#define XC4000_MN_NTSC_PAL_Mono 3 +#define XC4000_BG_PAL_A2 4 +#define XC4000_BG_PAL_NICAM 5 +#define XC4000_BG_PAL_MONO 6 +#define XC4000_I_PAL_NICAM 7 +#define XC4000_I_PAL_NICAM_MONO 8 +#define XC4000_DK_PAL_A2 9 +#define XC4000_DK_PAL_NICAM 10 +#define XC4000_DK_PAL_MONO 11 +#define XC4000_DK_SECAM_A2DK1 12 +#define XC4000_DK_SECAM_A2LDK3 13 +#define XC4000_DK_SECAM_A2MONO 14 +#define XC4000_DK_SECAM_NICAM 15 +#define XC4000_L_SECAM_NICAM 16 +#define XC4000_LC_SECAM_NICAM 17 +#define XC4000_DTV6 18 +#define XC4000_DTV8 19 +#define XC4000_DTV7_8 20 +#define XC4000_DTV7 21 +#define XC4000_FM_Radio_INPUT2 22 +#define XC4000_FM_Radio_INPUT1 23 + +static struct XC_TV_STANDARD xc4000_standard[MAX_TV_STANDARD] = { + {"M/N-NTSC/PAL-BTSC", 0x0000, 0x80A0, 4500}, + {"M/N-NTSC/PAL-A2", 0x0000, 0x80A0, 4600}, + {"M/N-NTSC/PAL-EIAJ", 0x0040, 0x80A0, 4500}, + {"M/N-NTSC/PAL-Mono", 0x0078, 0x80A0, 4500}, + {"B/G-PAL-A2", 0x0000, 0x8159, 5640}, + {"B/G-PAL-NICAM", 0x0004, 0x8159, 5740}, + {"B/G-PAL-MONO", 0x0078, 0x8159, 5500}, + {"I-PAL-NICAM", 0x0080, 0x8049, 6240}, + {"I-PAL-NICAM-MONO", 0x0078, 0x8049, 6000}, + {"D/K-PAL-A2", 0x0000, 0x8049, 6380}, + {"D/K-PAL-NICAM", 0x0080, 0x8049, 6200}, + {"D/K-PAL-MONO", 0x0078, 0x8049, 6500}, + {"D/K-SECAM-A2 DK1", 0x0000, 0x8049, 6340}, + {"D/K-SECAM-A2 L/DK3", 0x0000, 0x8049, 6000}, + {"D/K-SECAM-A2 MONO", 0x0078, 0x8049, 6500}, + {"D/K-SECAM-NICAM", 0x0080, 0x8049, 6200}, + {"L-SECAM-NICAM", 0x8080, 0x0009, 6200}, + {"L'-SECAM-NICAM", 0x8080, 0x4009, 6200}, + {"DTV6", 0x00C0, 0x8002, 0}, + {"DTV8", 0x00C0, 0x800B, 0}, + {"DTV7/8", 0x00C0, 0x801B, 0}, + {"DTV7", 0x00C0, 0x8007, 0}, + {"FM Radio-INPUT2", 0x0008, 0x9800, 10700}, + {"FM Radio-INPUT1", 0x0008, 0x9000, 10700} +}; + +static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val); +static int xc4000_tuner_reset(struct dvb_frontend *fe); +static void xc_debug_dump(struct xc4000_priv *priv); + +static int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len) +{ + struct i2c_msg msg = { .addr = priv->i2c_props.addr, + .flags = 0, .buf = buf, .len = len }; + if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { + if (priv->ignore_i2c_write_errors == 0) { + printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n", + len); + if (len == 4) { + printk(KERN_ERR "bytes %02x %02x %02x %02x\n", buf[0], + buf[1], buf[2], buf[3]); + } + return -EREMOTEIO; + } + } + return 0; +} + +static int xc4000_tuner_reset(struct dvb_frontend *fe) +{ + struct xc4000_priv *priv = fe->tuner_priv; + int ret; + + dprintk(1, "%s()\n", __func__); + + if (fe->callback) { + ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? + fe->dvb->priv : + priv->i2c_props.adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, + XC4000_TUNER_RESET, 0); + if (ret) { + printk(KERN_ERR "xc4000: reset failed\n"); + return -EREMOTEIO; + } + } else { + printk(KERN_ERR "xc4000: no tuner reset callback function, " + "fatal\n"); + return -EINVAL; + } + return 0; +} + +static int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData) +{ + u8 buf[4]; + int result; + + buf[0] = (regAddr >> 8) & 0xFF; + buf[1] = regAddr & 0xFF; + buf[2] = (i2cData >> 8) & 0xFF; + buf[3] = i2cData & 0xFF; + result = xc_send_i2c_data(priv, buf, 4); + + return result; +} + +static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) +{ + struct xc4000_priv *priv = fe->tuner_priv; + + int i, nbytes_to_send, result; + unsigned int len, pos, index; + u8 buf[XC_MAX_I2C_WRITE_LENGTH]; + + index = 0; + while ((i2c_sequence[index] != 0xFF) || + (i2c_sequence[index + 1] != 0xFF)) { + len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; + if (len == 0x0000) { + /* RESET command */ + /* NOTE: this is ignored, as the reset callback was */ + /* already called by check_firmware() */ + index += 2; + } else if (len & 0x8000) { + /* WAIT command */ + msleep(len & 0x7FFF); + index += 2; + } else { + /* Send i2c data whilst ensuring individual transactions + * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. + */ + index += 2; + buf[0] = i2c_sequence[index]; + buf[1] = i2c_sequence[index + 1]; + pos = 2; + while (pos < len) { + if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) + nbytes_to_send = + XC_MAX_I2C_WRITE_LENGTH; + else + nbytes_to_send = (len - pos + 2); + for (i = 2; i < nbytes_to_send; i++) { + buf[i] = i2c_sequence[index + pos + + i - 2]; + } + result = xc_send_i2c_data(priv, buf, + nbytes_to_send); + + if (result != 0) + return result; + + pos += nbytes_to_send - 2; + } + index += len; + } + } + return 0; +} + +static int xc_set_tv_standard(struct xc4000_priv *priv, + u16 video_mode, u16 audio_mode) +{ + int ret; + dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode); + dprintk(1, "%s() Standard = %s\n", + __func__, + xc4000_standard[priv->video_standard].Name); + + /* Don't complain when the request fails because of i2c stretching */ + priv->ignore_i2c_write_errors = 1; + + ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode); + if (ret == 0) + ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode); + + priv->ignore_i2c_write_errors = 0; + + return ret; +} + +static int xc_set_signal_source(struct xc4000_priv *priv, u16 rf_mode) +{ + dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, + rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); + + if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { + rf_mode = XC_RF_MODE_CABLE; + printk(KERN_ERR + "%s(), Invalid mode, defaulting to CABLE", + __func__); + } + return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); +} + +static const struct dvb_tuner_ops xc4000_tuner_ops; + +static int xc_set_rf_frequency(struct xc4000_priv *priv, u32 freq_hz) +{ + u16 freq_code; + + dprintk(1, "%s(%u)\n", __func__, freq_hz); + + if ((freq_hz > xc4000_tuner_ops.info.frequency_max) || + (freq_hz < xc4000_tuner_ops.info.frequency_min)) + return -EINVAL; + + freq_code = (u16)(freq_hz / 15625); + + /* WAS: Starting in firmware version 1.1.44, Xceive recommends using the + FINERFREQ for all normal tuning (the doc indicates reg 0x03 should + only be used for fast scanning for channel lock) */ + /* WAS: XREG_FINERFREQ */ + return xc_write_reg(priv, XREG_RF_FREQ, freq_code); +} + +static int xc_get_adc_envelope(struct xc4000_priv *priv, u16 *adc_envelope) +{ + return xc4000_readreg(priv, XREG_ADC_ENV, adc_envelope); +} + +static int xc_get_frequency_error(struct xc4000_priv *priv, u32 *freq_error_hz) +{ + int result; + u16 regData; + u32 tmp; + + result = xc4000_readreg(priv, XREG_FREQ_ERROR, ®Data); + if (result != 0) + return result; + + tmp = (u32)regData & 0xFFFFU; + tmp = (tmp < 0x8000U ? tmp : 0x10000U - tmp); + (*freq_error_hz) = tmp * 15625; + return result; +} + +static int xc_get_lock_status(struct xc4000_priv *priv, u16 *lock_status) +{ + return xc4000_readreg(priv, XREG_LOCK, lock_status); +} + +static int xc_get_version(struct xc4000_priv *priv, + u8 *hw_majorversion, u8 *hw_minorversion, + u8 *fw_majorversion, u8 *fw_minorversion) +{ + u16 data; + int result; + + result = xc4000_readreg(priv, XREG_VERSION, &data); + if (result != 0) + return result; + + (*hw_majorversion) = (data >> 12) & 0x0F; + (*hw_minorversion) = (data >> 8) & 0x0F; + (*fw_majorversion) = (data >> 4) & 0x0F; + (*fw_minorversion) = data & 0x0F; + + return 0; +} + +static int xc_get_hsync_freq(struct xc4000_priv *priv, u32 *hsync_freq_hz) +{ + u16 regData; + int result; + + result = xc4000_readreg(priv, XREG_HSYNC_FREQ, ®Data); + if (result != 0) + return result; + + (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; + return result; +} + +static int xc_get_frame_lines(struct xc4000_priv *priv, u16 *frame_lines) +{ + return xc4000_readreg(priv, XREG_FRAME_LINES, frame_lines); +} + +static int xc_get_quality(struct xc4000_priv *priv, u16 *quality) +{ + return xc4000_readreg(priv, XREG_QUALITY, quality); +} + +static u16 xc_wait_for_lock(struct xc4000_priv *priv) +{ + u16 lock_state = 0; + int watchdog_count = 40; + + while ((lock_state == 0) && (watchdog_count > 0)) { + xc_get_lock_status(priv, &lock_state); + if (lock_state != 1) { + msleep(5); + watchdog_count--; + } + } + return lock_state; +} + +static int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz) +{ + int found = 1; + int result; + + dprintk(1, "%s(%u)\n", __func__, freq_hz); + + /* Don't complain when the request fails because of i2c stretching */ + priv->ignore_i2c_write_errors = 1; + result = xc_set_rf_frequency(priv, freq_hz); + priv->ignore_i2c_write_errors = 0; + + if (result != 0) + return 0; + + /* wait for lock only in analog TV mode */ + if ((priv->cur_fw.type & (FM | DTV6 | DTV7 | DTV78 | DTV8)) == 0) { + if (xc_wait_for_lock(priv) != 1) + found = 0; + } + + /* Wait for stats to stabilize. + * Frame Lines needs two frame times after initial lock + * before it is valid. + */ + msleep(debug ? 100 : 10); + + if (debug) + xc_debug_dump(priv); + + return found; +} + +static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val) +{ + u8 buf[2] = { reg >> 8, reg & 0xff }; + u8 bval[2] = { 0, 0 }; + struct i2c_msg msg[2] = { + { .addr = priv->i2c_props.addr, + .flags = 0, .buf = &buf[0], .len = 2 }, + { .addr = priv->i2c_props.addr, + .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, + }; + + if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { + printk(KERN_ERR "xc4000: I2C read failed\n"); + return -EREMOTEIO; + } + + *val = (bval[0] << 8) | bval[1]; + return 0; +} + +#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) +static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) +{ + if (type & BASE) + printk(KERN_CONT "BASE "); + if (type & INIT1) + printk(KERN_CONT "INIT1 "); + if (type & F8MHZ) + printk(KERN_CONT "F8MHZ "); + if (type & MTS) + printk(KERN_CONT "MTS "); + if (type & D2620) + printk(KERN_CONT "D2620 "); + if (type & D2633) + printk(KERN_CONT "D2633 "); + if (type & DTV6) + printk(KERN_CONT "DTV6 "); + if (type & QAM) + printk(KERN_CONT "QAM "); + if (type & DTV7) + printk(KERN_CONT "DTV7 "); + if (type & DTV78) + printk(KERN_CONT "DTV78 "); + if (type & DTV8) + printk(KERN_CONT "DTV8 "); + if (type & FM) + printk(KERN_CONT "FM "); + if (type & INPUT1) + printk(KERN_CONT "INPUT1 "); + if (type & LCD) + printk(KERN_CONT "LCD "); + if (type & NOGD) + printk(KERN_CONT "NOGD "); + if (type & MONO) + printk(KERN_CONT "MONO "); + if (type & ATSC) + printk(KERN_CONT "ATSC "); + if (type & IF) + printk(KERN_CONT "IF "); + if (type & LG60) + printk(KERN_CONT "LG60 "); + if (type & ATI638) + printk(KERN_CONT "ATI638 "); + if (type & OREN538) + printk(KERN_CONT "OREN538 "); + if (type & OREN36) + printk(KERN_CONT "OREN36 "); + if (type & TOYOTA388) + printk(KERN_CONT "TOYOTA388 "); + if (type & TOYOTA794) + printk(KERN_CONT "TOYOTA794 "); + if (type & DIBCOM52) + printk(KERN_CONT "DIBCOM52 "); + if (type & ZARLINK456) + printk(KERN_CONT "ZARLINK456 "); + if (type & CHINA) + printk(KERN_CONT "CHINA "); + if (type & F6MHZ) + printk(KERN_CONT "F6MHZ "); + if (type & INPUT2) + printk(KERN_CONT "INPUT2 "); + if (type & SCODE) + printk(KERN_CONT "SCODE "); + if (type & HAS_IF) + printk(KERN_CONT "HAS_IF_%d ", int_freq); +} + +static int seek_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) +{ + struct xc4000_priv *priv = fe->tuner_priv; + int i, best_i = -1; + unsigned int best_nr_diffs = 255U; + + if (!priv->firm) { + printk(KERN_ERR "Error! firmware not loaded\n"); + return -EINVAL; + } + + if (((type & ~SCODE) == 0) && (*id == 0)) + *id = V4L2_STD_PAL; + + /* Seek for generic video standard match */ + for (i = 0; i < priv->firm_size; i++) { + v4l2_std_id id_diff_mask = + (priv->firm[i].id ^ (*id)) & (*id); + unsigned int type_diff_mask = + (priv->firm[i].type ^ type) + & (BASE_TYPES | DTV_TYPES | LCD | NOGD | MONO | SCODE); + unsigned int nr_diffs; + + if (type_diff_mask + & (BASE | INIT1 | FM | DTV6 | DTV7 | DTV78 | DTV8 | SCODE)) + continue; + + nr_diffs = hweight64(id_diff_mask) + hweight32(type_diff_mask); + if (!nr_diffs) /* Supports all the requested standards */ + goto found; + + if (nr_diffs < best_nr_diffs) { + best_nr_diffs = nr_diffs; + best_i = i; + } + } + + /* FIXME: Would make sense to seek for type "hint" match ? */ + if (best_i < 0) { + i = -ENOENT; + goto ret; + } + + if (best_nr_diffs > 0U) { + printk(KERN_WARNING + "Selecting best matching firmware (%u bits differ) for " + "type=(%x), id %016llx:\n", + best_nr_diffs, type, (unsigned long long)*id); + i = best_i; + } + +found: + *id = priv->firm[i].id; + +ret: + if (debug) { + printk(KERN_DEBUG "%s firmware for type=", + (i < 0) ? "Can't find" : "Found"); + dump_firm_type(type); + printk(KERN_DEBUG "(%x), id %016llx.\n", type, (unsigned long long)*id); + } + return i; +} + +static int load_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) +{ + struct xc4000_priv *priv = fe->tuner_priv; + int pos, rc; + unsigned char *p; + + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + + p = priv->firm[pos].ptr; + + /* Don't complain when the request fails because of i2c stretching */ + priv->ignore_i2c_write_errors = 1; + + rc = xc_load_i2c_sequence(fe, p); + + priv->ignore_i2c_write_errors = 0; + + return rc; +} + +static int xc4000_fwupload(struct dvb_frontend *fe) +{ + struct xc4000_priv *priv = fe->tuner_priv; + const struct firmware *fw = NULL; + const unsigned char *p, *endp; + int rc = 0; + int n, n_array; + char name[33]; + const char *fname; + + if (firmware_name[0] != '\0') + fname = firmware_name; + else + fname = XC4000_DEFAULT_FIRMWARE; + + dprintk(1, "Reading firmware %s\n", fname); + rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent); + if (rc < 0) { + if (rc == -ENOENT) + printk(KERN_ERR "Error: firmware %s not found.\n", fname); + else + printk(KERN_ERR "Error %d while requesting firmware %s\n", + rc, fname); + + return rc; + } + p = fw->data; + endp = p + fw->size; + + if (fw->size < sizeof(name) - 1 + 2 + 2) { + printk(KERN_ERR "Error: firmware file %s has invalid size!\n", + fname); + goto corrupt; + } + + memcpy(name, p, sizeof(name) - 1); + name[sizeof(name) - 1] = '\0'; + p += sizeof(name) - 1; + + priv->firm_version = get_unaligned_le16(p); + p += 2; + + n_array = get_unaligned_le16(p); + p += 2; + + dprintk(1, "Loading %d firmware images from %s, type: %s, ver %d.%d\n", + n_array, fname, name, + priv->firm_version >> 8, priv->firm_version & 0xff); + + priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); + if (priv->firm == NULL) { + printk(KERN_ERR "Not enough memory to load firmware file.\n"); + rc = -ENOMEM; + goto done; + } + priv->firm_size = n_array; + + n = -1; + while (p < endp) { + __u32 type, size; + v4l2_std_id id; + __u16 int_freq = 0; + + n++; + if (n >= n_array) { + printk(KERN_ERR "More firmware images in file than " + "were expected!\n"); + goto corrupt; + } + + /* Checks if there's enough bytes to read */ + if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) + goto header; + + type = get_unaligned_le32(p); + p += sizeof(type); + + id = get_unaligned_le64(p); + p += sizeof(id); + + if (type & HAS_IF) { + int_freq = get_unaligned_le16(p); + p += sizeof(int_freq); + if (endp - p < sizeof(size)) + goto header; + } + + size = get_unaligned_le32(p); + p += sizeof(size); + + if (!size || size > endp - p) { + printk(KERN_ERR "Firmware type (%x), id %llx is corrupted (size=%d, expected %d)\n", + type, (unsigned long long)id, + (unsigned)(endp - p), size); + goto corrupt; + } + + priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); + if (priv->firm[n].ptr == NULL) { + printk(KERN_ERR "Not enough memory to load firmware file.\n"); + rc = -ENOMEM; + goto done; + } + + if (debug) { + printk(KERN_DEBUG "Reading firmware type "); + dump_firm_type_and_int_freq(type, int_freq); + printk(KERN_DEBUG "(%x), id %llx, size=%d.\n", + type, (unsigned long long)id, size); + } + + memcpy(priv->firm[n].ptr, p, size); + priv->firm[n].type = type; + priv->firm[n].id = id; + priv->firm[n].size = size; + priv->firm[n].int_freq = int_freq; + + p += size; + } + + if (n + 1 != priv->firm_size) { + printk(KERN_ERR "Firmware file is incomplete!\n"); + goto corrupt; + } + + goto done; + +header: + printk(KERN_ERR "Firmware header is incomplete!\n"); +corrupt: + rc = -EINVAL; + printk(KERN_ERR "Error: firmware file is corrupted!\n"); + +done: + release_firmware(fw); + if (rc == 0) + dprintk(1, "Firmware files loaded.\n"); + + return rc; +} + +static int load_scode(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id, __u16 int_freq, int scode) +{ + struct xc4000_priv *priv = fe->tuner_priv; + int pos, rc; + unsigned char *p; + u8 scode_buf[13]; + u8 indirect_mode[5]; + + dprintk(1, "%s called int_freq=%d\n", __func__, int_freq); + + if (!int_freq) { + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + } else { + for (pos = 0; pos < priv->firm_size; pos++) { + if ((priv->firm[pos].int_freq == int_freq) && + (priv->firm[pos].type & HAS_IF)) + break; + } + if (pos == priv->firm_size) + return -ENOENT; + } + + p = priv->firm[pos].ptr; + + if (priv->firm[pos].size != 12 * 16 || scode >= 16) + return -EINVAL; + p += 12 * scode; + + if (debug) { + tuner_info("Loading SCODE for type="); + dump_firm_type_and_int_freq(priv->firm[pos].type, + priv->firm[pos].int_freq); + printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type, + (unsigned long long)*id); + } + + scode_buf[0] = 0x00; + memcpy(&scode_buf[1], p, 12); + + /* Enter direct-mode */ + rc = xc_write_reg(priv, XREG_DIRECTSITTING_MODE, 0); + if (rc < 0) { + printk(KERN_ERR "failed to put device into direct mode!\n"); + return -EIO; + } + + rc = xc_send_i2c_data(priv, scode_buf, 13); + if (rc != 0) { + /* Even if the send failed, make sure we set back to indirect + mode */ + printk(KERN_ERR "Failed to set scode %d\n", rc); + } + + /* Switch back to indirect-mode */ + memset(indirect_mode, 0, sizeof(indirect_mode)); + indirect_mode[4] = 0x88; + xc_send_i2c_data(priv, indirect_mode, sizeof(indirect_mode)); + msleep(10); + + return 0; +} + +static int check_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id std, __u16 int_freq) +{ + struct xc4000_priv *priv = fe->tuner_priv; + struct firmware_properties new_fw; + int rc = 0, is_retry = 0; + u16 hwmodel; + v4l2_std_id std0; + u8 hw_major, hw_minor, fw_major, fw_minor; + + dprintk(1, "%s called\n", __func__); + + if (!priv->firm) { + rc = xc4000_fwupload(fe); + if (rc < 0) + return rc; + } + +retry: + new_fw.type = type; + new_fw.id = std; + new_fw.std_req = std; + new_fw.scode_table = SCODE; + new_fw.scode_nr = 0; + new_fw.int_freq = int_freq; + + dprintk(1, "checking firmware, user requested type="); + if (debug) { + dump_firm_type(new_fw.type); + printk(KERN_CONT "(%x), id %016llx, ", new_fw.type, + (unsigned long long)new_fw.std_req); + if (!int_freq) + printk(KERN_CONT "scode_tbl "); + else + printk(KERN_CONT "int_freq %d, ", new_fw.int_freq); + printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr); + } + + /* No need to reload base firmware if it matches */ + if (priv->cur_fw.type & BASE) { + dprintk(1, "BASE firmware not changed.\n"); + goto skip_base; + } + + /* Updating BASE - forget about all currently loaded firmware */ + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); + + /* Reset is needed before loading firmware */ + rc = xc4000_tuner_reset(fe); + if (rc < 0) + goto fail; + + /* BASE firmwares are all std0 */ + std0 = 0; + rc = load_firmware(fe, BASE, &std0); + if (rc < 0) { + printk(KERN_ERR "Error %d while loading base firmware\n", rc); + goto fail; + } + + /* Load INIT1, if needed */ + dprintk(1, "Load init1 firmware, if exists\n"); + + rc = load_firmware(fe, BASE | INIT1, &std0); + if (rc == -ENOENT) + rc = load_firmware(fe, BASE | INIT1, &std0); + if (rc < 0 && rc != -ENOENT) { + tuner_err("Error %d while loading init1 firmware\n", + rc); + goto fail; + } + +skip_base: + /* + * No need to reload standard specific firmware if base firmware + * was not reloaded and requested video standards have not changed. + */ + if (priv->cur_fw.type == (BASE | new_fw.type) && + priv->cur_fw.std_req == std) { + dprintk(1, "Std-specific firmware already loaded.\n"); + goto skip_std_specific; + } + + /* Reloading std-specific firmware forces a SCODE update */ + priv->cur_fw.scode_table = 0; + + /* Load the standard firmware */ + rc = load_firmware(fe, new_fw.type, &new_fw.id); + + if (rc < 0) + goto fail; + +skip_std_specific: + if (priv->cur_fw.scode_table == new_fw.scode_table && + priv->cur_fw.scode_nr == new_fw.scode_nr) { + dprintk(1, "SCODE firmware already loaded.\n"); + goto check_device; + } + + /* Load SCODE firmware, if exists */ + rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, + new_fw.int_freq, new_fw.scode_nr); + if (rc != 0) + dprintk(1, "load scode failed %d\n", rc); + +check_device: + rc = xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel); + + if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major, + &fw_minor) != 0) { + printk(KERN_ERR "Unable to read tuner registers.\n"); + goto fail; + } + + dprintk(1, "Device is Xceive %d version %d.%d, " + "firmware version %d.%d\n", + hwmodel, hw_major, hw_minor, fw_major, fw_minor); + + /* Check firmware version against what we downloaded. */ + if (priv->firm_version != ((fw_major << 8) | fw_minor)) { + printk(KERN_WARNING + "Incorrect readback of firmware version %d.%d.\n", + fw_major, fw_minor); + goto fail; + } + + /* Check that the tuner hardware model remains consistent over time. */ + if (priv->hwmodel == 0 && + (hwmodel == XC_PRODUCT_ID_XC4000 || + hwmodel == XC_PRODUCT_ID_XC4100)) { + priv->hwmodel = hwmodel; + priv->hwvers = (hw_major << 8) | hw_minor; + } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || + priv->hwvers != ((hw_major << 8) | hw_minor)) { + printk(KERN_WARNING + "Read invalid device hardware information - tuner " + "hung?\n"); + goto fail; + } + + memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); + + /* + * By setting BASE in cur_fw.type only after successfully loading all + * firmwares, we can: + * 1. Identify that BASE firmware with type=0 has been loaded; + * 2. Tell whether BASE firmware was just changed the next time through. + */ + priv->cur_fw.type |= BASE; + + return 0; + +fail: + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); + if (!is_retry) { + msleep(50); + is_retry = 1; + dprintk(1, "Retrying firmware load\n"); + goto retry; + } + + if (rc == -ENOENT) + rc = -EINVAL; + return rc; +} + +static void xc_debug_dump(struct xc4000_priv *priv) +{ + u16 adc_envelope; + u32 freq_error_hz = 0; + u16 lock_status; + u32 hsync_freq_hz = 0; + u16 frame_lines; + u16 quality; + u8 hw_majorversion = 0, hw_minorversion = 0; + u8 fw_majorversion = 0, fw_minorversion = 0; + + xc_get_adc_envelope(priv, &adc_envelope); + dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); + + xc_get_frequency_error(priv, &freq_error_hz); + dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); + + xc_get_lock_status(priv, &lock_status); + dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", + lock_status); + + xc_get_version(priv, &hw_majorversion, &hw_minorversion, + &fw_majorversion, &fw_minorversion); + dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n", + hw_majorversion, hw_minorversion, + fw_majorversion, fw_minorversion); + + if (priv->video_standard < XC4000_DTV6) { + xc_get_hsync_freq(priv, &hsync_freq_hz); + dprintk(1, "*** Horizontal sync frequency = %d Hz\n", + hsync_freq_hz); + + xc_get_frame_lines(priv, &frame_lines); + dprintk(1, "*** Frame lines = %d\n", frame_lines); + } + + xc_get_quality(priv, &quality); + dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); +} + +static int xc4000_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct xc4000_priv *priv = fe->tuner_priv; + unsigned int type; + int ret = -EREMOTEIO; + + dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency); + + mutex_lock(&priv->lock); + + if (fe->ops.info.type == FE_ATSC) { + dprintk(1, "%s() ATSC\n", __func__); + switch (params->u.vsb.modulation) { + case VSB_8: + case VSB_16: + dprintk(1, "%s() VSB modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_AIR; + priv->freq_hz = params->frequency - 1750000; + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = XC4000_DTV6; + type = DTV6; + break; + case QAM_64: + case QAM_256: + case QAM_AUTO: + dprintk(1, "%s() QAM modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_CABLE; + priv->freq_hz = params->frequency - 1750000; + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = XC4000_DTV6; + type = DTV6; + break; + default: + ret = -EINVAL; + goto fail; + } + } else if (fe->ops.info.type == FE_OFDM) { + dprintk(1, "%s() OFDM\n", __func__); + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = XC4000_DTV6; + priv->freq_hz = params->frequency - 1750000; + type = DTV6; + break; + case BANDWIDTH_7_MHZ: + priv->bandwidth = BANDWIDTH_7_MHZ; + priv->video_standard = XC4000_DTV7; + priv->freq_hz = params->frequency - 2250000; + type = DTV7; + break; + case BANDWIDTH_8_MHZ: + priv->bandwidth = BANDWIDTH_8_MHZ; + priv->video_standard = XC4000_DTV8; + priv->freq_hz = params->frequency - 2750000; + type = DTV8; + break; + case BANDWIDTH_AUTO: + if (params->frequency < 400000000) { + priv->bandwidth = BANDWIDTH_7_MHZ; + priv->freq_hz = params->frequency - 2250000; + } else { + priv->bandwidth = BANDWIDTH_8_MHZ; + priv->freq_hz = params->frequency - 2750000; + } + priv->video_standard = XC4000_DTV7_8; + type = DTV78; + break; + default: + printk(KERN_ERR "xc4000 bandwidth not set!\n"); + ret = -EINVAL; + goto fail; + } + priv->rf_mode = XC_RF_MODE_AIR; + } else { + printk(KERN_ERR "xc4000 modulation type not supported!\n"); + ret = -EINVAL; + goto fail; + } + + dprintk(1, "%s() frequency=%d (compensated)\n", + __func__, priv->freq_hz); + + /* Make sure the correct firmware type is loaded */ + if (check_firmware(fe, type, 0, priv->if_khz) != 0) + goto fail; + + ret = xc_set_signal_source(priv, priv->rf_mode); + if (ret != 0) { + printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n", + priv->rf_mode); + goto fail; + } else { + u16 video_mode, audio_mode; + video_mode = xc4000_standard[priv->video_standard].video_mode; + audio_mode = xc4000_standard[priv->video_standard].audio_mode; + if (type == DTV6 && priv->firm_version != 0x0102) + video_mode |= 0x0001; + ret = xc_set_tv_standard(priv, video_mode, audio_mode); + if (ret != 0) { + printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n"); + /* DJH - do not return when it fails... */ + /* goto fail; */ + } + } + + if (xc_write_reg(priv, XREG_D_CODE, 0) == 0) + ret = 0; + if (priv->dvb_amplitude != 0) { + if (xc_write_reg(priv, XREG_AMPLITUDE, + (priv->firm_version != 0x0102 || + priv->dvb_amplitude != 134 ? + priv->dvb_amplitude : 132)) != 0) + ret = -EREMOTEIO; + } + if (priv->set_smoothedcvbs != 0) { + if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0) + ret = -EREMOTEIO; + } + if (ret != 0) { + printk(KERN_ERR "xc4000: setting registers failed\n"); + /* goto fail; */ + } + + xc_tune_channel(priv, priv->freq_hz); + + ret = 0; + +fail: + mutex_unlock(&priv->lock); + + return ret; +} + +static int xc4000_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct xc4000_priv *priv = fe->tuner_priv; + unsigned int type = 0; + int ret = -EREMOTEIO; + + if (params->mode == V4L2_TUNER_RADIO) { + dprintk(1, "%s() frequency=%d (in units of 62.5Hz)\n", + __func__, params->frequency); + + mutex_lock(&priv->lock); + + params->std = 0; + priv->freq_hz = params->frequency * 125L / 2; + + if (audio_std & XC4000_AUDIO_STD_INPUT1) { + priv->video_standard = XC4000_FM_Radio_INPUT1; + type = FM | INPUT1; + } else { + priv->video_standard = XC4000_FM_Radio_INPUT2; + type = FM | INPUT2; + } + + goto tune_channel; + } + + dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", + __func__, params->frequency); + + mutex_lock(&priv->lock); + + /* params->frequency is in units of 62.5khz */ + priv->freq_hz = params->frequency * 62500; + + params->std &= V4L2_STD_ALL; + /* if std is not defined, choose one */ + if (!params->std) + params->std = V4L2_STD_PAL_BG; + + if (audio_std & XC4000_AUDIO_STD_MONO) + type = MONO; + + if (params->std & V4L2_STD_MN) { + params->std = V4L2_STD_MN; + if (audio_std & XC4000_AUDIO_STD_MONO) { + priv->video_standard = XC4000_MN_NTSC_PAL_Mono; + } else if (audio_std & XC4000_AUDIO_STD_A2) { + params->std |= V4L2_STD_A2; + priv->video_standard = XC4000_MN_NTSC_PAL_A2; + } else { + params->std |= V4L2_STD_BTSC; + priv->video_standard = XC4000_MN_NTSC_PAL_BTSC; + } + goto tune_channel; + } + + if (params->std & V4L2_STD_PAL_BG) { + params->std = V4L2_STD_PAL_BG; + if (audio_std & XC4000_AUDIO_STD_MONO) { + priv->video_standard = XC4000_BG_PAL_MONO; + } else if (!(audio_std & XC4000_AUDIO_STD_A2)) { + if (!(audio_std & XC4000_AUDIO_STD_B)) { + params->std |= V4L2_STD_NICAM_A; + priv->video_standard = XC4000_BG_PAL_NICAM; + } else { + params->std |= V4L2_STD_NICAM_B; + priv->video_standard = XC4000_BG_PAL_NICAM; + } + } else { + if (!(audio_std & XC4000_AUDIO_STD_B)) { + params->std |= V4L2_STD_A2_A; + priv->video_standard = XC4000_BG_PAL_A2; + } else { + params->std |= V4L2_STD_A2_B; + priv->video_standard = XC4000_BG_PAL_A2; + } + } + goto tune_channel; + } + + if (params->std & V4L2_STD_PAL_I) { + /* default to NICAM audio standard */ + params->std = V4L2_STD_PAL_I | V4L2_STD_NICAM; + if (audio_std & XC4000_AUDIO_STD_MONO) + priv->video_standard = XC4000_I_PAL_NICAM_MONO; + else + priv->video_standard = XC4000_I_PAL_NICAM; + goto tune_channel; + } + + if (params->std & V4L2_STD_PAL_DK) { + params->std = V4L2_STD_PAL_DK; + if (audio_std & XC4000_AUDIO_STD_MONO) { + priv->video_standard = XC4000_DK_PAL_MONO; + } else if (audio_std & XC4000_AUDIO_STD_A2) { + params->std |= V4L2_STD_A2; + priv->video_standard = XC4000_DK_PAL_A2; + } else { + params->std |= V4L2_STD_NICAM; + priv->video_standard = XC4000_DK_PAL_NICAM; + } + goto tune_channel; + } + + if (params->std & V4L2_STD_SECAM_DK) { + /* default to A2 audio standard */ + params->std = V4L2_STD_SECAM_DK | V4L2_STD_A2; + if (audio_std & XC4000_AUDIO_STD_L) { + type = 0; + priv->video_standard = XC4000_DK_SECAM_NICAM; + } else if (audio_std & XC4000_AUDIO_STD_MONO) { + priv->video_standard = XC4000_DK_SECAM_A2MONO; + } else if (audio_std & XC4000_AUDIO_STD_K3) { + params->std |= V4L2_STD_SECAM_K3; + priv->video_standard = XC4000_DK_SECAM_A2LDK3; + } else { + priv->video_standard = XC4000_DK_SECAM_A2DK1; + } + goto tune_channel; + } + + if (params->std & V4L2_STD_SECAM_L) { + /* default to NICAM audio standard */ + type = 0; + params->std = V4L2_STD_SECAM_L | V4L2_STD_NICAM; + priv->video_standard = XC4000_L_SECAM_NICAM; + goto tune_channel; + } + + if (params->std & V4L2_STD_SECAM_LC) { + /* default to NICAM audio standard */ + type = 0; + params->std = V4L2_STD_SECAM_LC | V4L2_STD_NICAM; + priv->video_standard = XC4000_LC_SECAM_NICAM; + goto tune_channel; + } + +tune_channel: + /* FIXME: it could be air. */ + priv->rf_mode = XC_RF_MODE_CABLE; + + if (check_firmware(fe, type, params->std, + xc4000_standard[priv->video_standard].int_freq) != 0) + goto fail; + + ret = xc_set_signal_source(priv, priv->rf_mode); + if (ret != 0) { + printk(KERN_ERR + "xc4000: xc_set_signal_source(%d) failed\n", + priv->rf_mode); + goto fail; + } else { + u16 video_mode, audio_mode; + video_mode = xc4000_standard[priv->video_standard].video_mode; + audio_mode = xc4000_standard[priv->video_standard].audio_mode; + if (priv->video_standard < XC4000_BG_PAL_A2) { + if (type & NOGD) + video_mode &= 0xFF7F; + } else if (priv->video_standard < XC4000_I_PAL_NICAM) { + if (priv->firm_version == 0x0102) + video_mode &= 0xFEFF; + if (audio_std & XC4000_AUDIO_STD_B) + video_mode |= 0x0080; + } + ret = xc_set_tv_standard(priv, video_mode, audio_mode); + if (ret != 0) { + printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n"); + goto fail; + } + } + + if (xc_write_reg(priv, XREG_D_CODE, 0) == 0) + ret = 0; + if (xc_write_reg(priv, XREG_AMPLITUDE, 1) != 0) + ret = -EREMOTEIO; + if (priv->set_smoothedcvbs != 0) { + if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0) + ret = -EREMOTEIO; + } + if (ret != 0) { + printk(KERN_ERR "xc4000: setting registers failed\n"); + goto fail; + } + + xc_tune_channel(priv, priv->freq_hz); + + ret = 0; + +fail: + mutex_unlock(&priv->lock); + + return ret; +} + +static int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq) +{ + struct xc4000_priv *priv = fe->tuner_priv; + + *freq = priv->freq_hz; + + if (debug) { + mutex_lock(&priv->lock); + if ((priv->cur_fw.type + & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) { + u16 snr = 0; + if (xc4000_readreg(priv, XREG_SNR, &snr) == 0) { + mutex_unlock(&priv->lock); + dprintk(1, "%s() freq = %u, SNR = %d\n", + __func__, *freq, snr); + return 0; + } + } + mutex_unlock(&priv->lock); + } + + dprintk(1, "%s()\n", __func__); + + return 0; +} + +static int xc4000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) +{ + struct xc4000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + + *bw = priv->bandwidth; + return 0; +} + +static int xc4000_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct xc4000_priv *priv = fe->tuner_priv; + u16 lock_status = 0; + + mutex_lock(&priv->lock); + + if (priv->cur_fw.type & BASE) + xc_get_lock_status(priv, &lock_status); + + *status = (lock_status == 1 ? + TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO : 0); + if (priv->cur_fw.type & (DTV6 | DTV7 | DTV78 | DTV8)) + *status &= (~TUNER_STATUS_STEREO); + + mutex_unlock(&priv->lock); + + dprintk(2, "%s() lock_status = %d\n", __func__, lock_status); + + return 0; +} + +static int xc4000_sleep(struct dvb_frontend *fe) +{ + struct xc4000_priv *priv = fe->tuner_priv; + int ret = 0; + + dprintk(1, "%s()\n", __func__); + + mutex_lock(&priv->lock); + + /* Avoid firmware reload on slow devices */ + if ((no_poweroff == 2 || + (no_poweroff == 0 && priv->default_pm != 0)) && + (priv->cur_fw.type & BASE) != 0) { + /* force reset and firmware reload */ + priv->cur_fw.type = XC_POWERED_DOWN; + + if (xc_write_reg(priv, XREG_POWER_DOWN, 0) != 0) { + printk(KERN_ERR + "xc4000: %s() unable to shutdown tuner\n", + __func__); + ret = -EREMOTEIO; + } + msleep(20); + } + + mutex_unlock(&priv->lock); + + return ret; +} + +static int xc4000_init(struct dvb_frontend *fe) +{ + dprintk(1, "%s()\n", __func__); + + return 0; +} + +static int xc4000_release(struct dvb_frontend *fe) +{ + struct xc4000_priv *priv = fe->tuner_priv; + + dprintk(1, "%s()\n", __func__); + + mutex_lock(&xc4000_list_mutex); + + if (priv) + hybrid_tuner_release_state(priv); + + mutex_unlock(&xc4000_list_mutex); + + fe->tuner_priv = NULL; + + return 0; +} + +static const struct dvb_tuner_ops xc4000_tuner_ops = { + .info = { + .name = "Xceive XC4000", + .frequency_min = 1000000, + .frequency_max = 1023000000, + .frequency_step = 50000, + }, + + .release = xc4000_release, + .init = xc4000_init, + .sleep = xc4000_sleep, + + .set_params = xc4000_set_params, + .set_analog_params = xc4000_set_analog_params, + .get_frequency = xc4000_get_frequency, + .get_bandwidth = xc4000_get_bandwidth, + .get_status = xc4000_get_status +}; + +struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct xc4000_config *cfg) +{ + struct xc4000_priv *priv = NULL; + int instance; + u16 id = 0; + + dprintk(1, "%s(%d-%04x)\n", __func__, + i2c ? i2c_adapter_id(i2c) : -1, + cfg ? cfg->i2c_address : -1); + + mutex_lock(&xc4000_list_mutex); + + instance = hybrid_tuner_request_state(struct xc4000_priv, priv, + hybrid_tuner_instance_list, + i2c, cfg->i2c_address, "xc4000"); + switch (instance) { + case 0: + goto fail; + break; + case 1: + /* new tuner instance */ + priv->bandwidth = BANDWIDTH_6_MHZ; + /* set default configuration */ + priv->if_khz = 4560; + priv->default_pm = 0; + priv->dvb_amplitude = 134; + priv->set_smoothedcvbs = 1; + mutex_init(&priv->lock); + fe->tuner_priv = priv; + break; + default: + /* existing tuner instance */ + fe->tuner_priv = priv; + break; + } + + if (cfg->if_khz != 0) { + /* copy configuration if provided by the caller */ + priv->if_khz = cfg->if_khz; + priv->default_pm = cfg->default_pm; + priv->dvb_amplitude = cfg->dvb_amplitude; + priv->set_smoothedcvbs = cfg->set_smoothedcvbs; + } + + /* Check if firmware has been loaded. It is possible that another + instance of the driver has loaded the firmware. + */ + + if (instance == 1) { + if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) + goto fail; + } else { + id = ((priv->cur_fw.type & BASE) != 0 ? + priv->hwmodel : XC_PRODUCT_ID_FW_NOT_LOADED); + } + + switch (id) { + case XC_PRODUCT_ID_XC4000: + case XC_PRODUCT_ID_XC4100: + printk(KERN_INFO + "xc4000: Successfully identified at address 0x%02x\n", + cfg->i2c_address); + printk(KERN_INFO + "xc4000: Firmware has been loaded previously\n"); + break; + case XC_PRODUCT_ID_FW_NOT_LOADED: + printk(KERN_INFO + "xc4000: Successfully identified at address 0x%02x\n", + cfg->i2c_address); + printk(KERN_INFO + "xc4000: Firmware has not been loaded previously\n"); + break; + default: + printk(KERN_ERR + "xc4000: Device not found at addr 0x%02x (0x%x)\n", + cfg->i2c_address, id); + goto fail; + } + + mutex_unlock(&xc4000_list_mutex); + + memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + if (instance == 1) { + int ret; + mutex_lock(&priv->lock); + ret = xc4000_fwupload(fe); + mutex_unlock(&priv->lock); + if (ret != 0) + goto fail2; + } + + return fe; +fail: + mutex_unlock(&xc4000_list_mutex); +fail2: + xc4000_release(fe); + return NULL; +} +EXPORT_SYMBOL(xc4000_attach); + +MODULE_AUTHOR("Steven Toth, Davide Ferri"); +MODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/xc4000.h b/drivers/media/common/tuners/xc4000.h new file mode 100644 index 0000000000000000000000000000000000000000..e6a44d151cbdd9701d81db0794d40d87548e4e14 --- /dev/null +++ b/drivers/media/common/tuners/xc4000.h @@ -0,0 +1,67 @@ +/* + * Driver for Xceive XC4000 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2007 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __XC4000_H__ +#define __XC4000_H__ + +#include + +struct dvb_frontend; +struct i2c_adapter; + +struct xc4000_config { + u8 i2c_address; + /* if non-zero, power management is enabled by default */ + u8 default_pm; + /* value to be written to XREG_AMPLITUDE in DVB-T mode (0: no write) */ + u8 dvb_amplitude; + /* if non-zero, register 0x0E is set to filter analog TV video output */ + u8 set_smoothedcvbs; + /* IF for DVB-T */ + u32 if_khz; +}; + +/* xc4000 callback command */ +#define XC4000_TUNER_RESET 0 + +/* For each bridge framework, when it attaches either analog or digital, + * it has to store a reference back to its _core equivalent structure, + * so that it can service the hardware by steering gpio's etc. + * Each bridge implementation is different so cast devptr accordingly. + * The xc4000 driver cares not for this value, other than ensuring + * it's passed back to a bridge during tuner_callback(). + */ + +#if defined(CONFIG_MEDIA_TUNER_XC4000) || (defined(CONFIG_MEDIA_TUNER_XC4000_MODULE) && defined(MODULE)) +extern struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct xc4000_config *cfg); +#else +static inline struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct xc4000_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index ee214c3b63d7050c8629f14ee8a6f148a1d881d2..f6e40b3a44cc2204f842969deec3ea72c3170b21 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -80,6 +80,10 @@ comment "Supported nGene Adapters" depends on DVB_CORE && PCI && I2C source "drivers/media/dvb/ngene/Kconfig" +comment "Supported ddbridge ('Octopus') Adapters" + depends on DVB_CORE && PCI && I2C + source "drivers/media/dvb/ddbridge/Kconfig" + comment "Supported DVB Frontends" depends on DVB_CORE source "drivers/media/dvb/frontends/Kconfig" diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index a1a08758a6f28122439381cf7f19eb5daa028029..b2cefe637a6410e42bb3ccc762beaa3c3b28901f 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -15,6 +15,7 @@ obj-y := dvb-core/ \ dm1105/ \ pt1/ \ mantis/ \ - ngene/ + ngene/ \ + ddbridge/ obj-$(CONFIG_DVB_FIREDTV) += firewire/ diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 1e1106dcd063ebd687d552bcc493873fcd5c8a8b..521d691049824523f7229335bf0eb267f976376f 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -892,7 +892,7 @@ static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub) if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) { printk("dvb_bt8xx: no pci device for card %d\n", card->bttv_nr); kfree(card); - return -EFAULT; + return -ENODEV; } if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) { @@ -902,7 +902,7 @@ static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub) "installed, try removing it.\n"); kfree(card); - return -EFAULT; + return -ENODEV; } mutex_init(&card->bt->gpio_lock); diff --git a/drivers/media/dvb/ddbridge/Kconfig b/drivers/media/dvb/ddbridge/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..d099e1a12c85ec0e6b03673f404a9714eb3dc2d0 --- /dev/null +++ b/drivers/media/dvb/ddbridge/Kconfig @@ -0,0 +1,18 @@ +config DVB_DDBRIDGE + tristate "Digital Devices bridge support" + depends on DVB_CORE && PCI && I2C + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_STV6110x if !DVB_FE_CUSTOMISE + select DVB_STV090x if !DVB_FE_CUSTOMISE + select DVB_DRXK if !DVB_FE_CUSTOMISE + select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE + ---help--- + Support for cards with the Digital Devices PCI express bridge: + - Octopus PCIe Bridge + - Octopus mini PCIe Bridge + - Octopus LE + - DuoFlex S2 Octopus + - DuoFlex CT Octopus + - cineS2(v6) + + Say Y if you own such a card and want to use it. diff --git a/drivers/media/dvb/ddbridge/Makefile b/drivers/media/dvb/ddbridge/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..de4fe193c3efc76524f4ea07a13fe7e07b35f5b6 --- /dev/null +++ b/drivers/media/dvb/ddbridge/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the ddbridge device driver +# + +ddbridge-objs := ddbridge-core.o + +obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/ +EXTRA_CFLAGS += -Idrivers/media/common/tuners/ + +# For the staging CI driver cxd2099 +EXTRA_CFLAGS += -Idrivers/staging/cxd2099/ diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c new file mode 100644 index 0000000000000000000000000000000000000000..573d540f213e3365566c72753dd4709ee4b765fc --- /dev/null +++ b/drivers/media/dvb/ddbridge/ddbridge-core.c @@ -0,0 +1,1719 @@ +/* + * ddbridge.c: Digital Devices PCIe bridge driver + * + * Copyright (C) 2010-2011 Digital Devices GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ddbridge.h" + +#include "ddbridge-regs.h" + +#include "tda18271c2dd.h" +#include "stv6110x.h" +#include "stv090x.h" +#include "lnbh24.h" +#include "drxk.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +/* MSI had problems with lost interrupts, fixed but needs testing */ +#undef CONFIG_PCI_MSI + +/******************************************************************************/ + +static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) +{ + struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1 } }; + return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; +} + +static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val) +{ + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = ®, .len = 1 }, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1 } }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, + u16 reg, u8 *val) +{ + u8 msg[2] = {reg>>8, reg&0xff}; + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = msg, .len = 2}, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1} }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) +{ + struct ddb *dev = i2c->dev; + int stat; + u32 val; + + i2c->done = 0; + ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND); + stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ); + if (stat <= 0) { + printk(KERN_ERR "I2C timeout\n"); + { /* MSI debugging*/ + u32 istat = ddbreadl(INTERRUPT_STATUS); + printk(KERN_ERR "IRS %08x\n", istat); + ddbwritel(istat, INTERRUPT_ACK); + } + return -EIO; + } + val = ddbreadl(i2c->regs+I2C_COMMAND); + if (val & 0x70000) + return -EIO; + return 0; +} + +static int ddb_i2c_master_xfer(struct i2c_adapter *adapter, + struct i2c_msg msg[], int num) +{ + struct ddb_i2c *i2c = (struct ddb_i2c *)i2c_get_adapdata(adapter); + struct ddb *dev = i2c->dev; + u8 addr = 0; + + if (num) + addr = msg[0].addr; + + if (num == 2 && msg[1].flags & I2C_M_RD && + !(msg[0].flags & I2C_M_RD)) { + memcpy_toio(dev->regs + I2C_TASKMEM_BASE + i2c->wbuf, + msg[0].buf, msg[0].len); + ddbwritel(msg[0].len|(msg[1].len << 16), + i2c->regs+I2C_TASKLENGTH); + if (!ddb_i2c_cmd(i2c, addr, 1)) { + memcpy_fromio(msg[1].buf, + dev->regs + I2C_TASKMEM_BASE + i2c->rbuf, + msg[1].len); + return num; + } + } + + if (num == 1 && !(msg[0].flags & I2C_M_RD)) { + ddbcpyto(I2C_TASKMEM_BASE + i2c->wbuf, msg[0].buf, msg[0].len); + ddbwritel(msg[0].len, i2c->regs + I2C_TASKLENGTH); + if (!ddb_i2c_cmd(i2c, addr, 2)) + return num; + } + if (num == 1 && (msg[0].flags & I2C_M_RD)) { + ddbwritel(msg[0].len << 16, i2c->regs + I2C_TASKLENGTH); + if (!ddb_i2c_cmd(i2c, addr, 3)) { + ddbcpyfrom(msg[0].buf, + I2C_TASKMEM_BASE + i2c->rbuf, msg[0].len); + return num; + } + } + return -EIO; +} + + +static u32 ddb_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +struct i2c_algorithm ddb_i2c_algo = { + .master_xfer = ddb_i2c_master_xfer, + .functionality = ddb_i2c_functionality, +}; + +static void ddb_i2c_release(struct ddb *dev) +{ + int i; + struct ddb_i2c *i2c; + struct i2c_adapter *adap; + + for (i = 0; i < dev->info->port_num; i++) { + i2c = &dev->i2c[i]; + adap = &i2c->adap; + i2c_del_adapter(adap); + } +} + +static int ddb_i2c_init(struct ddb *dev) +{ + int i, j, stat = 0; + struct ddb_i2c *i2c; + struct i2c_adapter *adap; + + for (i = 0; i < dev->info->port_num; i++) { + i2c = &dev->i2c[i]; + i2c->dev = dev; + i2c->nr = i; + i2c->wbuf = i * (I2C_TASKMEM_SIZE / 4); + i2c->rbuf = i2c->wbuf + (I2C_TASKMEM_SIZE / 8); + i2c->regs = 0x80 + i * 0x20; + ddbwritel(I2C_SPEED_100, i2c->regs + I2C_TIMING); + ddbwritel((i2c->rbuf << 16) | i2c->wbuf, + i2c->regs + I2C_TASKADDRESS); + init_waitqueue_head(&i2c->wq); + + adap = &i2c->adap; + i2c_set_adapdata(adap, i2c); +#ifdef I2C_ADAP_CLASS_TV_DIGITAL + adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG; +#else +#ifdef I2C_CLASS_TV_ANALOG + adap->class = I2C_CLASS_TV_ANALOG; +#endif +#endif + strcpy(adap->name, "ddbridge"); + adap->algo = &ddb_i2c_algo; + adap->algo_data = (void *)i2c; + adap->dev.parent = &dev->pdev->dev; + stat = i2c_add_adapter(adap); + if (stat) + break; + } + if (stat) + for (j = 0; j < i; j++) { + i2c = &dev->i2c[j]; + adap = &i2c->adap; + i2c_del_adapter(adap); + } + return stat; +} + + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + +#if 0 +static void set_table(struct ddb *dev, u32 off, + dma_addr_t *pbuf, u32 num) +{ + u32 i, base; + u64 mem; + + base = DMA_BASE_ADDRESS_TABLE + off; + for (i = 0; i < num; i++) { + mem = pbuf[i]; + ddbwritel(mem & 0xffffffff, base + i * 8); + ddbwritel(mem >> 32, base + i * 8 + 4); + } +} +#endif + +static void ddb_address_table(struct ddb *dev) +{ + u32 i, j, base; + u64 mem; + dma_addr_t *pbuf; + + for (i = 0; i < dev->info->port_num * 2; i++) { + base = DMA_BASE_ADDRESS_TABLE + i * 0x100; + pbuf = dev->input[i].pbuf; + for (j = 0; j < dev->input[i].dma_buf_num; j++) { + mem = pbuf[j]; + ddbwritel(mem & 0xffffffff, base + j * 8); + ddbwritel(mem >> 32, base + j * 8 + 4); + } + } + for (i = 0; i < dev->info->port_num; i++) { + base = DMA_BASE_ADDRESS_TABLE + 0x800 + i * 0x100; + pbuf = dev->output[i].pbuf; + for (j = 0; j < dev->output[i].dma_buf_num; j++) { + mem = pbuf[j]; + ddbwritel(mem & 0xffffffff, base + j * 8); + ddbwritel(mem >> 32, base + j * 8 + 4); + } + } +} + +static void io_free(struct pci_dev *pdev, u8 **vbuf, + dma_addr_t *pbuf, u32 size, int num) +{ + int i; + + for (i = 0; i < num; i++) { + if (vbuf[i]) { + pci_free_consistent(pdev, size, vbuf[i], pbuf[i]); + vbuf[i] = 0; + } + } +} + +static int io_alloc(struct pci_dev *pdev, u8 **vbuf, + dma_addr_t *pbuf, u32 size, int num) +{ + int i; + + for (i = 0; i < num; i++) { + vbuf[i] = pci_alloc_consistent(pdev, size, &pbuf[i]); + if (!vbuf[i]) + return -ENOMEM; + } + return 0; +} + +static int ddb_buffers_alloc(struct ddb *dev) +{ + int i; + struct ddb_port *port; + + for (i = 0; i < dev->info->port_num; i++) { + port = &dev->port[i]; + switch (port->class) { + case DDB_PORT_TUNER: + if (io_alloc(dev->pdev, port->input[0]->vbuf, + port->input[0]->pbuf, + port->input[0]->dma_buf_size, + port->input[0]->dma_buf_num) < 0) + return -1; + if (io_alloc(dev->pdev, port->input[1]->vbuf, + port->input[1]->pbuf, + port->input[1]->dma_buf_size, + port->input[1]->dma_buf_num) < 0) + return -1; + break; + case DDB_PORT_CI: + if (io_alloc(dev->pdev, port->input[0]->vbuf, + port->input[0]->pbuf, + port->input[0]->dma_buf_size, + port->input[0]->dma_buf_num) < 0) + return -1; + if (io_alloc(dev->pdev, port->output->vbuf, + port->output->pbuf, + port->output->dma_buf_size, + port->output->dma_buf_num) < 0) + return -1; + break; + default: + break; + } + } + ddb_address_table(dev); + return 0; +} + +static void ddb_buffers_free(struct ddb *dev) +{ + int i; + struct ddb_port *port; + + for (i = 0; i < dev->info->port_num; i++) { + port = &dev->port[i]; + io_free(dev->pdev, port->input[0]->vbuf, + port->input[0]->pbuf, + port->input[0]->dma_buf_size, + port->input[0]->dma_buf_num); + io_free(dev->pdev, port->input[1]->vbuf, + port->input[1]->pbuf, + port->input[1]->dma_buf_size, + port->input[1]->dma_buf_num); + io_free(dev->pdev, port->output->vbuf, + port->output->pbuf, + port->output->dma_buf_size, + port->output->dma_buf_num); + } +} + +static void ddb_input_start(struct ddb_input *input) +{ + struct ddb *dev = input->port->dev; + + spin_lock_irq(&input->lock); + input->cbuf = 0; + input->coff = 0; + + /* reset */ + ddbwritel(0, TS_INPUT_CONTROL(input->nr)); + ddbwritel(2, TS_INPUT_CONTROL(input->nr)); + ddbwritel(0, TS_INPUT_CONTROL(input->nr)); + + ddbwritel((1 << 16) | + (input->dma_buf_num << 11) | + (input->dma_buf_size >> 7), + DMA_BUFFER_SIZE(input->nr)); + ddbwritel(0, DMA_BUFFER_ACK(input->nr)); + + ddbwritel(1, DMA_BASE_WRITE); + ddbwritel(3, DMA_BUFFER_CONTROL(input->nr)); + ddbwritel(9, TS_INPUT_CONTROL(input->nr)); + input->running = 1; + spin_unlock_irq(&input->lock); +} + +static void ddb_input_stop(struct ddb_input *input) +{ + struct ddb *dev = input->port->dev; + + spin_lock_irq(&input->lock); + ddbwritel(0, TS_INPUT_CONTROL(input->nr)); + ddbwritel(0, DMA_BUFFER_CONTROL(input->nr)); + input->running = 0; + spin_unlock_irq(&input->lock); +} + +static void ddb_output_start(struct ddb_output *output) +{ + struct ddb *dev = output->port->dev; + + spin_lock_irq(&output->lock); + output->cbuf = 0; + output->coff = 0; + ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); + ddbwritel(2, TS_OUTPUT_CONTROL(output->nr)); + ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); + ddbwritel(0x3c, TS_OUTPUT_CONTROL(output->nr)); + ddbwritel((1 << 16) | + (output->dma_buf_num << 11) | + (output->dma_buf_size >> 7), + DMA_BUFFER_SIZE(output->nr + 8)); + ddbwritel(0, DMA_BUFFER_ACK(output->nr + 8)); + + ddbwritel(1, DMA_BASE_READ); + ddbwritel(3, DMA_BUFFER_CONTROL(output->nr + 8)); + /* ddbwritel(0xbd, TS_OUTPUT_CONTROL(output->nr)); */ + ddbwritel(0x1d, TS_OUTPUT_CONTROL(output->nr)); + output->running = 1; + spin_unlock_irq(&output->lock); +} + +static void ddb_output_stop(struct ddb_output *output) +{ + struct ddb *dev = output->port->dev; + + spin_lock_irq(&output->lock); + ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); + ddbwritel(0, DMA_BUFFER_CONTROL(output->nr + 8)); + output->running = 0; + spin_unlock_irq(&output->lock); +} + +static u32 ddb_output_free(struct ddb_output *output) +{ + u32 idx, off, stat = output->stat; + s32 diff; + + idx = (stat >> 11) & 0x1f; + off = (stat & 0x7ff) << 7; + + if (output->cbuf != idx) { + if ((((output->cbuf + 1) % output->dma_buf_num) == idx) && + (output->dma_buf_size - output->coff <= 188)) + return 0; + return 188; + } + diff = off - output->coff; + if (diff <= 0 || diff > 188) + return 188; + return 0; +} + +static ssize_t ddb_output_write(struct ddb_output *output, + const u8 *buf, size_t count) +{ + struct ddb *dev = output->port->dev; + u32 idx, off, stat = output->stat; + u32 left = count, len; + + idx = (stat >> 11) & 0x1f; + off = (stat & 0x7ff) << 7; + + while (left) { + len = output->dma_buf_size - output->coff; + if ((((output->cbuf + 1) % output->dma_buf_num) == idx) && + (off == 0)) { + if (len <= 188) + break; + len -= 188; + } + if (output->cbuf == idx) { + if (off > output->coff) { +#if 1 + len = off - output->coff; + len -= (len % 188); + if (len <= 188) + +#endif + break; + len -= 188; + } + } + if (len > left) + len = left; + if (copy_from_user(output->vbuf[output->cbuf] + output->coff, + buf, len)) + return -EIO; + left -= len; + buf += len; + output->coff += len; + if (output->coff == output->dma_buf_size) { + output->coff = 0; + output->cbuf = ((output->cbuf + 1) % output->dma_buf_num); + } + ddbwritel((output->cbuf << 11) | (output->coff >> 7), + DMA_BUFFER_ACK(output->nr + 8)); + } + return count - left; +} + +static u32 ddb_input_avail(struct ddb_input *input) +{ + struct ddb *dev = input->port->dev; + u32 idx, off, stat = input->stat; + u32 ctrl = ddbreadl(DMA_BUFFER_CONTROL(input->nr)); + + idx = (stat >> 11) & 0x1f; + off = (stat & 0x7ff) << 7; + + if (ctrl & 4) { + printk(KERN_ERR "IA %d %d %08x\n", idx, off, ctrl); + ddbwritel(input->stat, DMA_BUFFER_ACK(input->nr)); + return 0; + } + if (input->cbuf != idx) + return 188; + return 0; +} + +static size_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count) +{ + struct ddb *dev = input->port->dev; + u32 left = count; + u32 idx, off, free, stat = input->stat; + int ret; + + idx = (stat >> 11) & 0x1f; + off = (stat & 0x7ff) << 7; + + while (left) { + if (input->cbuf == idx) + return count - left; + free = input->dma_buf_size - input->coff; + if (free > left) + free = left; + ret = copy_to_user(buf, input->vbuf[input->cbuf] + + input->coff, free); + input->coff += free; + if (input->coff == input->dma_buf_size) { + input->coff = 0; + input->cbuf = (input->cbuf+1) % input->dma_buf_num; + } + left -= free; + ddbwritel((input->cbuf << 11) | (input->coff >> 7), + DMA_BUFFER_ACK(input->nr)); + } + return count; +} + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + +#if 0 +static struct ddb_input *fe2input(struct ddb *dev, struct dvb_frontend *fe) +{ + int i; + + for (i = 0; i < dev->info->port_num * 2; i++) { + if (dev->input[i].fe == fe) + return &dev->input[i]; + } + return NULL; +} +#endif + +static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct ddb_input *input = fe->sec_priv; + struct ddb_port *port = input->port; + int status; + + if (enable) { + mutex_lock(&port->i2c_gate_lock); + status = input->gate_ctrl(fe, 1); + } else { + status = input->gate_ctrl(fe, 0); + mutex_unlock(&port->i2c_gate_lock); + } + return status; +} + +static int demod_attach_drxk(struct ddb_input *input) +{ + struct i2c_adapter *i2c = &input->port->i2c->adap; + struct dvb_frontend *fe; + struct drxk_config config; + + memset(&config, 0, sizeof(config)); + config.adr = 0x29 + (input->nr & 1); + + fe = input->fe = dvb_attach(drxk_attach, &config, i2c, &input->fe2); + if (!input->fe) { + printk(KERN_ERR "No DRXK found!\n"); + return -ENODEV; + } + fe->sec_priv = input; + input->gate_ctrl = fe->ops.i2c_gate_ctrl; + fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; + return 0; +} + +static int tuner_attach_tda18271(struct ddb_input *input) +{ + struct i2c_adapter *i2c = &input->port->i2c->adap; + struct dvb_frontend *fe; + + if (input->fe->ops.i2c_gate_ctrl) + input->fe->ops.i2c_gate_ctrl(input->fe, 1); + fe = dvb_attach(tda18271c2dd_attach, input->fe, i2c, 0x60); + if (!fe) { + printk(KERN_ERR "No TDA18271 found!\n"); + return -ENODEV; + } + if (input->fe->ops.i2c_gate_ctrl) + input->fe->ops.i2c_gate_ctrl(input->fe, 0); + return 0; +} + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + +static struct stv090x_config stv0900 = { + .device = STV0900, + .demod_mode = STV090x_DUAL, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 27000000, + .address = 0x69, + + .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + + .repeater_level = STV090x_RPTLEVEL_16, + + .adc1_range = STV090x_ADC_1Vpp, + .adc2_range = STV090x_ADC_1Vpp, + + .diseqc_envelope_mode = true, +}; + +static struct stv090x_config stv0900_aa = { + .device = STV0900, + .demod_mode = STV090x_DUAL, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 27000000, + .address = 0x68, + + .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + + .repeater_level = STV090x_RPTLEVEL_16, + + .adc1_range = STV090x_ADC_1Vpp, + .adc2_range = STV090x_ADC_1Vpp, + + .diseqc_envelope_mode = true, +}; + +static struct stv6110x_config stv6110a = { + .addr = 0x60, + .refclk = 27000000, + .clk_div = 1, +}; + +static struct stv6110x_config stv6110b = { + .addr = 0x63, + .refclk = 27000000, + .clk_div = 1, +}; + +static int demod_attach_stv0900(struct ddb_input *input, int type) +{ + struct i2c_adapter *i2c = &input->port->i2c->adap; + struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900; + + input->fe = dvb_attach(stv090x_attach, feconf, i2c, + (input->nr & 1) ? STV090x_DEMODULATOR_1 + : STV090x_DEMODULATOR_0); + if (!input->fe) { + printk(KERN_ERR "No STV0900 found!\n"); + return -ENODEV; + } + if (!dvb_attach(lnbh24_attach, input->fe, i2c, 0, + 0, (input->nr & 1) ? + (0x09 - type) : (0x0b - type))) { + printk(KERN_ERR "No LNBH24 found!\n"); + return -ENODEV; + } + return 0; +} + +static int tuner_attach_stv6110(struct ddb_input *input, int type) +{ + struct i2c_adapter *i2c = &input->port->i2c->adap; + struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900; + struct stv6110x_config *tunerconf = (input->nr & 1) ? + &stv6110b : &stv6110a; + struct stv6110x_devctl *ctl; + + ctl = dvb_attach(stv6110x_attach, input->fe, tunerconf, i2c); + if (!ctl) { + printk(KERN_ERR "No STV6110X found!\n"); + return -ENODEV; + } + printk(KERN_INFO "attach tuner input %d adr %02x\n", + input->nr, tunerconf->addr); + + feconf->tuner_init = ctl->tuner_init; + feconf->tuner_sleep = ctl->tuner_sleep; + feconf->tuner_set_mode = ctl->tuner_set_mode; + feconf->tuner_set_frequency = ctl->tuner_set_frequency; + feconf->tuner_get_frequency = ctl->tuner_get_frequency; + feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth; + feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth; + feconf->tuner_set_bbgain = ctl->tuner_set_bbgain; + feconf->tuner_get_bbgain = ctl->tuner_get_bbgain; + feconf->tuner_set_refclk = ctl->tuner_set_refclk; + feconf->tuner_get_status = ctl->tuner_get_status; + + return 0; +} + +static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, + int (*start_feed)(struct dvb_demux_feed *), + int (*stop_feed)(struct dvb_demux_feed *), + void *priv) +{ + dvbdemux->priv = priv; + + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = start_feed; + dvbdemux->stop_feed = stop_feed; + dvbdemux->write_to_decoder = NULL; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING); + return dvb_dmx_init(dvbdemux); +} + +static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, + struct dvb_demux *dvbdemux, + struct dmx_frontend *hw_frontend, + struct dmx_frontend *mem_frontend, + struct dvb_adapter *dvb_adapter) +{ + int ret; + + dmxdev->filternum = 256; + dmxdev->demux = &dvbdemux->dmx; + dmxdev->capabilities = 0; + ret = dvb_dmxdev_init(dmxdev, dvb_adapter); + if (ret < 0) + return ret; + + hw_frontend->source = DMX_FRONTEND_0; + dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); + mem_frontend->source = DMX_MEMORY_FE; + dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); + return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); +} + +static int start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct ddb_input *input = dvbdmx->priv; + + if (!input->users) + ddb_input_start(input); + + return ++input->users; +} + +static int stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct ddb_input *input = dvbdmx->priv; + + if (--input->users) + return input->users; + + ddb_input_stop(input); + return 0; +} + + +static void dvb_input_detach(struct ddb_input *input) +{ + struct dvb_adapter *adap = &input->adap; + struct dvb_demux *dvbdemux = &input->demux; + + switch (input->attached) { + case 5: + if (input->fe2) + dvb_unregister_frontend(input->fe2); + if (input->fe) { + dvb_unregister_frontend(input->fe); + dvb_frontend_detach(input->fe); + input->fe = NULL; + } + case 4: + dvb_net_release(&input->dvbnet); + + case 3: + dvbdemux->dmx.close(&dvbdemux->dmx); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, + &input->hw_frontend); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, + &input->mem_frontend); + dvb_dmxdev_release(&input->dmxdev); + + case 2: + dvb_dmx_release(&input->demux); + + case 1: + dvb_unregister_adapter(adap); + } + input->attached = 0; +} + +static int dvb_input_attach(struct ddb_input *input) +{ + int ret; + struct ddb_port *port = input->port; + struct dvb_adapter *adap = &input->adap; + struct dvb_demux *dvbdemux = &input->demux; + + ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, + &input->port->dev->pdev->dev, + adapter_nr); + if (ret < 0) { + printk(KERN_ERR "ddbridge: Could not register adapter." + "Check if you enabled enough adapters in dvb-core!\n"); + return ret; + } + input->attached = 1; + + ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", + start_feed, + stop_feed, input); + if (ret < 0) + return ret; + input->attached = 2; + + ret = my_dvb_dmxdev_ts_card_init(&input->dmxdev, &input->demux, + &input->hw_frontend, + &input->mem_frontend, adap); + if (ret < 0) + return ret; + input->attached = 3; + + ret = dvb_net_init(adap, &input->dvbnet, input->dmxdev.demux); + if (ret < 0) + return ret; + input->attached = 4; + + input->fe = 0; + switch (port->type) { + case DDB_TUNER_DVBS_ST: + if (demod_attach_stv0900(input, 0) < 0) + return -ENODEV; + if (tuner_attach_stv6110(input, 0) < 0) + return -ENODEV; + if (input->fe) { + if (dvb_register_frontend(adap, input->fe) < 0) + return -ENODEV; + } + break; + case DDB_TUNER_DVBS_ST_AA: + if (demod_attach_stv0900(input, 1) < 0) + return -ENODEV; + if (tuner_attach_stv6110(input, 1) < 0) + return -ENODEV; + if (input->fe) { + if (dvb_register_frontend(adap, input->fe) < 0) + return -ENODEV; + } + break; + case DDB_TUNER_DVBCT_TR: + if (demod_attach_drxk(input) < 0) + return -ENODEV; + if (tuner_attach_tda18271(input) < 0) + return -ENODEV; + if (input->fe) { + if (dvb_register_frontend(adap, input->fe) < 0) + return -ENODEV; + } + if (input->fe2) { + if (dvb_register_frontend(adap, input->fe2) < 0) + return -ENODEV; + input->fe2->tuner_priv = input->fe->tuner_priv; + memcpy(&input->fe2->ops.tuner_ops, + &input->fe->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); + } + break; + } + input->attached = 5; + return 0; +} + +/****************************************************************************/ +/****************************************************************************/ + +static ssize_t ts_write(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct ddb_output *output = dvbdev->priv; + size_t left = count; + int stat; + + while (left) { + if (ddb_output_free(output) < 188) { + if (file->f_flags & O_NONBLOCK) + break; + if (wait_event_interruptible( + output->wq, ddb_output_free(output) >= 188) < 0) + break; + } + stat = ddb_output_write(output, buf, left); + if (stat < 0) + break; + buf += stat; + left -= stat; + } + return (left == count) ? -EAGAIN : (count - left); +} + +static ssize_t ts_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct ddb_output *output = dvbdev->priv; + struct ddb_input *input = output->port->input[0]; + int left, read; + + count -= count % 188; + left = count; + while (left) { + if (ddb_input_avail(input) < 188) { + if (file->f_flags & O_NONBLOCK) + break; + if (wait_event_interruptible( + input->wq, ddb_input_avail(input) >= 188) < 0) + break; + } + read = ddb_input_read(input, buf, left); + left -= read; + buf += read; + } + return (left == count) ? -EAGAIN : (count - left); +} + +static unsigned int ts_poll(struct file *file, poll_table *wait) +{ + /* + struct dvb_device *dvbdev = file->private_data; + struct ddb_output *output = dvbdev->priv; + struct ddb_input *input = output->port->input[0]; + */ + unsigned int mask = 0; + +#if 0 + if (data_avail_to_read) + mask |= POLLIN | POLLRDNORM; + if (data_avail_to_write) + mask |= POLLOUT | POLLWRNORM; + + poll_wait(file, &read_queue, wait); + poll_wait(file, &write_queue, wait); +#endif + return mask; +} + +static const struct file_operations ci_fops = { + .owner = THIS_MODULE, + .read = ts_read, + .write = ts_write, + .open = dvb_generic_open, + .release = dvb_generic_release, + .poll = ts_poll, + .mmap = 0, +}; + +static struct dvb_device dvbdev_ci = { + .priv = 0, + .readers = -1, + .writers = -1, + .users = -1, + .fops = &ci_fops, +}; + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static void input_tasklet(unsigned long data) +{ + struct ddb_input *input = (struct ddb_input *) data; + struct ddb *dev = input->port->dev; + + spin_lock(&input->lock); + if (!input->running) { + spin_unlock(&input->lock); + return; + } + input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr)); + + if (input->port->class == DDB_PORT_TUNER) { + if (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr))) + printk(KERN_ERR "Overflow input %d\n", input->nr); + while (input->cbuf != ((input->stat >> 11) & 0x1f) + || (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr)))) { + dvb_dmx_swfilter_packets(&input->demux, + input->vbuf[input->cbuf], + input->dma_buf_size / 188); + + input->cbuf = (input->cbuf + 1) % input->dma_buf_num; + ddbwritel((input->cbuf << 11), + DMA_BUFFER_ACK(input->nr)); + input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr)); + } + } + if (input->port->class == DDB_PORT_CI) + wake_up(&input->wq); + spin_unlock(&input->lock); +} + +static void output_tasklet(unsigned long data) +{ + struct ddb_output *output = (struct ddb_output *) data; + struct ddb *dev = output->port->dev; + + spin_lock(&output->lock); + if (!output->running) { + spin_unlock(&output->lock); + return; + } + output->stat = ddbreadl(DMA_BUFFER_CURRENT(output->nr + 8)); + wake_up(&output->wq); + spin_unlock(&output->lock); +} + + +struct cxd2099_cfg cxd_cfg = { + .bitrate = 62000, + .adr = 0x40, + .polarity = 1, + .clock_mode = 1, +}; + +static int ddb_ci_attach(struct ddb_port *port) +{ + int ret; + + ret = dvb_register_adapter(&port->output->adap, + "DDBridge", + THIS_MODULE, + &port->dev->pdev->dev, + adapter_nr); + if (ret < 0) + return ret; + port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); + if (!port->en) { + dvb_unregister_adapter(&port->output->adap); + return -ENODEV; + } + ddb_input_start(port->input[0]); + ddb_output_start(port->output); + dvb_ca_en50221_init(&port->output->adap, + port->en, 0, 1); + ret = dvb_register_device(&port->output->adap, &port->output->dev, + &dvbdev_ci, (void *) port->output, + DVB_DEVICE_SEC); + return ret; +} + +static int ddb_port_attach(struct ddb_port *port) +{ + int ret = 0; + + switch (port->class) { + case DDB_PORT_TUNER: + ret = dvb_input_attach(port->input[0]); + if (ret < 0) + break; + ret = dvb_input_attach(port->input[1]); + break; + case DDB_PORT_CI: + ret = ddb_ci_attach(port); + break; + default: + break; + } + if (ret < 0) + printk(KERN_ERR "port_attach on port %d failed\n", port->nr); + return ret; +} + +static int ddb_ports_attach(struct ddb *dev) +{ + int i, ret = 0; + struct ddb_port *port; + + for (i = 0; i < dev->info->port_num; i++) { + port = &dev->port[i]; + ret = ddb_port_attach(port); + if (ret < 0) + break; + } + return ret; +} + +static void ddb_ports_detach(struct ddb *dev) +{ + int i; + struct ddb_port *port; + + for (i = 0; i < dev->info->port_num; i++) { + port = &dev->port[i]; + switch (port->class) { + case DDB_PORT_TUNER: + dvb_input_detach(port->input[0]); + dvb_input_detach(port->input[1]); + break; + case DDB_PORT_CI: + if (port->output->dev) + dvb_unregister_device(port->output->dev); + if (port->en) { + ddb_input_stop(port->input[0]); + ddb_output_stop(port->output); + dvb_ca_en50221_release(port->en); + kfree(port->en); + port->en = 0; + dvb_unregister_adapter(&port->output->adap); + } + break; + } + } +} + +/****************************************************************************/ +/****************************************************************************/ + +static int port_has_ci(struct ddb_port *port) +{ + u8 val; + return i2c_read_reg(&port->i2c->adap, 0x40, 0, &val) ? 0 : 1; +} + +static int port_has_stv0900(struct ddb_port *port) +{ + u8 val; + if (i2c_read_reg16(&port->i2c->adap, 0x69, 0xf100, &val) < 0) + return 0; + return 1; +} + +static int port_has_stv0900_aa(struct ddb_port *port) +{ + u8 val; + if (i2c_read_reg16(&port->i2c->adap, 0x68, 0xf100, &val) < 0) + return 0; + return 1; +} + +static int port_has_drxks(struct ddb_port *port) +{ + u8 val; + if (i2c_read(&port->i2c->adap, 0x29, &val) < 0) + return 0; + if (i2c_read(&port->i2c->adap, 0x2a, &val) < 0) + return 0; + return 1; +} + +static void ddb_port_probe(struct ddb_port *port) +{ + struct ddb *dev = port->dev; + char *modname = "NO MODULE"; + + port->class = DDB_PORT_NONE; + + if (port_has_ci(port)) { + modname = "CI"; + port->class = DDB_PORT_CI; + ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); + } else if (port_has_stv0900(port)) { + modname = "DUAL DVB-S2"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_DVBS_ST; + ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING); + } else if (port_has_stv0900_aa(port)) { + modname = "DUAL DVB-S2"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_DVBS_ST_AA; + ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING); + } else if (port_has_drxks(port)) { + modname = "DUAL DVB-C/T"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_DVBCT_TR; + ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); + } + printk(KERN_INFO "Port %d (TAB %d): %s\n", + port->nr, port->nr+1, modname); +} + +static void ddb_input_init(struct ddb_port *port, int nr) +{ + struct ddb *dev = port->dev; + struct ddb_input *input = &dev->input[nr]; + + input->nr = nr; + input->port = port; + input->dma_buf_num = INPUT_DMA_BUFS; + input->dma_buf_size = INPUT_DMA_SIZE; + ddbwritel(0, TS_INPUT_CONTROL(nr)); + ddbwritel(2, TS_INPUT_CONTROL(nr)); + ddbwritel(0, TS_INPUT_CONTROL(nr)); + ddbwritel(0, DMA_BUFFER_ACK(nr)); + tasklet_init(&input->tasklet, input_tasklet, (unsigned long) input); + spin_lock_init(&input->lock); + init_waitqueue_head(&input->wq); +} + +static void ddb_output_init(struct ddb_port *port, int nr) +{ + struct ddb *dev = port->dev; + struct ddb_output *output = &dev->output[nr]; + output->nr = nr; + output->port = port; + output->dma_buf_num = OUTPUT_DMA_BUFS; + output->dma_buf_size = OUTPUT_DMA_SIZE; + + ddbwritel(0, TS_OUTPUT_CONTROL(nr)); + ddbwritel(2, TS_OUTPUT_CONTROL(nr)); + ddbwritel(0, TS_OUTPUT_CONTROL(nr)); + tasklet_init(&output->tasklet, output_tasklet, (unsigned long) output); + init_waitqueue_head(&output->wq); +} + +static void ddb_ports_init(struct ddb *dev) +{ + int i; + struct ddb_port *port; + + for (i = 0; i < dev->info->port_num; i++) { + port = &dev->port[i]; + port->dev = dev; + port->nr = i; + port->i2c = &dev->i2c[i]; + port->input[0] = &dev->input[2 * i]; + port->input[1] = &dev->input[2 * i + 1]; + port->output = &dev->output[i]; + + mutex_init(&port->i2c_gate_lock); + ddb_port_probe(port); + ddb_input_init(port, 2 * i); + ddb_input_init(port, 2 * i + 1); + ddb_output_init(port, i); + } +} + +static void ddb_ports_release(struct ddb *dev) +{ + int i; + struct ddb_port *port; + + for (i = 0; i < dev->info->port_num; i++) { + port = &dev->port[i]; + port->dev = dev; + tasklet_kill(&port->input[0]->tasklet); + tasklet_kill(&port->input[1]->tasklet); + tasklet_kill(&port->output->tasklet); + } +} + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static void irq_handle_i2c(struct ddb *dev, int n) +{ + struct ddb_i2c *i2c = &dev->i2c[n]; + + i2c->done = 1; + wake_up(&i2c->wq); +} + +static irqreturn_t irq_handler(int irq, void *dev_id) +{ + struct ddb *dev = (struct ddb *) dev_id; + u32 s = ddbreadl(INTERRUPT_STATUS); + + if (!s) + return IRQ_NONE; + + do { + ddbwritel(s, INTERRUPT_ACK); + + if (s & 0x00000001) + irq_handle_i2c(dev, 0); + if (s & 0x00000002) + irq_handle_i2c(dev, 1); + if (s & 0x00000004) + irq_handle_i2c(dev, 2); + if (s & 0x00000008) + irq_handle_i2c(dev, 3); + + if (s & 0x00000100) + tasklet_schedule(&dev->input[0].tasklet); + if (s & 0x00000200) + tasklet_schedule(&dev->input[1].tasklet); + if (s & 0x00000400) + tasklet_schedule(&dev->input[2].tasklet); + if (s & 0x00000800) + tasklet_schedule(&dev->input[3].tasklet); + if (s & 0x00001000) + tasklet_schedule(&dev->input[4].tasklet); + if (s & 0x00002000) + tasklet_schedule(&dev->input[5].tasklet); + if (s & 0x00004000) + tasklet_schedule(&dev->input[6].tasklet); + if (s & 0x00008000) + tasklet_schedule(&dev->input[7].tasklet); + + if (s & 0x00010000) + tasklet_schedule(&dev->output[0].tasklet); + if (s & 0x00020000) + tasklet_schedule(&dev->output[1].tasklet); + if (s & 0x00040000) + tasklet_schedule(&dev->output[2].tasklet); + if (s & 0x00080000) + tasklet_schedule(&dev->output[3].tasklet); + + /* if (s & 0x000f0000) printk(KERN_DEBUG "%08x\n", istat); */ + } while ((s = ddbreadl(INTERRUPT_STATUS))); + + return IRQ_HANDLED; +} + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + +static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) +{ + u32 data, shift; + + if (wlen > 4) + ddbwritel(1, SPI_CONTROL); + while (wlen > 4) { + /* FIXME: check for big-endian */ + data = swab32(*(u32 *)wbuf); + wbuf += 4; + wlen -= 4; + ddbwritel(data, SPI_DATA); + while (ddbreadl(SPI_CONTROL) & 0x0004) + ; + } + + if (rlen) + ddbwritel(0x0001 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); + else + ddbwritel(0x0003 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); + + data = 0; + shift = ((4 - wlen) * 8); + while (wlen) { + data <<= 8; + data |= *wbuf; + wlen--; + wbuf++; + } + if (shift) + data <<= shift; + ddbwritel(data, SPI_DATA); + while (ddbreadl(SPI_CONTROL) & 0x0004) + ; + + if (!rlen) { + ddbwritel(0, SPI_CONTROL); + return 0; + } + if (rlen > 4) + ddbwritel(1, SPI_CONTROL); + + while (rlen > 4) { + ddbwritel(0xffffffff, SPI_DATA); + while (ddbreadl(SPI_CONTROL) & 0x0004) + ; + data = ddbreadl(SPI_DATA); + *(u32 *) rbuf = swab32(data); + rbuf += 4; + rlen -= 4; + } + ddbwritel(0x0003 | ((rlen << (8 + 3)) & 0x1F00), SPI_CONTROL); + ddbwritel(0xffffffff, SPI_DATA); + while (ddbreadl(SPI_CONTROL) & 0x0004) + ; + + data = ddbreadl(SPI_DATA); + ddbwritel(0, SPI_CONTROL); + + if (rlen < 4) + data <<= ((4 - rlen) * 8); + + while (rlen > 0) { + *rbuf = ((data >> 24) & 0xff); + data <<= 8; + rbuf++; + rlen--; + } + return 0; +} + +#define DDB_MAGIC 'd' + +struct ddb_flashio { + __u8 *write_buf; + __u32 write_len; + __u8 *read_buf; + __u32 read_len; +}; + +#define IOCTL_DDB_FLASHIO _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio) + +#define DDB_NAME "ddbridge" + +static u32 ddb_num; +static struct ddb *ddbs[32]; +static struct class *ddb_class; +static int ddb_major; + +static int ddb_open(struct inode *inode, struct file *file) +{ + struct ddb *dev = ddbs[iminor(inode)]; + + file->private_data = dev; + return 0; +} + +static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct ddb *dev = file->private_data; + void *parg = (void *)arg; + int res = -EFAULT; + + switch (cmd) { + case IOCTL_DDB_FLASHIO: + { + struct ddb_flashio fio; + u8 *rbuf, *wbuf; + + if (copy_from_user(&fio, parg, sizeof(fio))) + break; + if (fio.write_len + fio.read_len > 1028) { + printk(KERN_ERR "IOBUF too small\n"); + return -ENOMEM; + } + wbuf = &dev->iobuf[0]; + if (!wbuf) + return -ENOMEM; + rbuf = wbuf + fio.write_len; + if (copy_from_user(wbuf, fio.write_buf, fio.write_len)) { + vfree(wbuf); + break; + } + res = flashio(dev, wbuf, fio.write_len, + rbuf, fio.read_len); + if (copy_to_user(fio.read_buf, rbuf, fio.read_len)) + res = -EFAULT; + break; + } + default: + break; + } + return res; +} + +static const struct file_operations ddb_fops = { + .unlocked_ioctl = ddb_ioctl, + .open = ddb_open, +}; + +static char *ddb_devnode(struct device *device, mode_t *mode) +{ + struct ddb *dev = dev_get_drvdata(device); + + return kasprintf(GFP_KERNEL, "ddbridge/card%d", dev->nr); +} + +static int ddb_class_create(void) +{ + ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops); + if (ddb_major < 0) + return ddb_major; + + ddb_class = class_create(THIS_MODULE, DDB_NAME); + if (IS_ERR(ddb_class)) { + unregister_chrdev(ddb_major, DDB_NAME); + return -1; + } + ddb_class->devnode = ddb_devnode; + return 0; +} + +static void ddb_class_destroy(void) +{ + class_destroy(ddb_class); + unregister_chrdev(ddb_major, DDB_NAME); +} + +static int ddb_device_create(struct ddb *dev) +{ + dev->nr = ddb_num++; + dev->ddb_dev = device_create(ddb_class, NULL, + MKDEV(ddb_major, dev->nr), + dev, "ddbridge%d", dev->nr); + ddbs[dev->nr] = dev; + if (IS_ERR(dev->ddb_dev)) + return -1; + return 0; +} + +static void ddb_device_destroy(struct ddb *dev) +{ + ddb_num--; + if (IS_ERR(dev->ddb_dev)) + return; + device_destroy(ddb_class, MKDEV(ddb_major, 0)); +} + + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static void ddb_unmap(struct ddb *dev) +{ + if (dev->regs) + iounmap(dev->regs); + vfree(dev); +} + + +static void __devexit ddb_remove(struct pci_dev *pdev) +{ + struct ddb *dev = (struct ddb *) pci_get_drvdata(pdev); + + ddb_ports_detach(dev); + ddb_i2c_release(dev); + + ddbwritel(0, INTERRUPT_ENABLE); + free_irq(dev->pdev->irq, dev); +#ifdef CONFIG_PCI_MSI + if (dev->msi) + pci_disable_msi(dev->pdev); +#endif + ddb_ports_release(dev); + ddb_buffers_free(dev); + ddb_device_destroy(dev); + + ddb_unmap(dev); + pci_set_drvdata(pdev, 0); + pci_disable_device(pdev); +} + + +static int __devinit ddb_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct ddb *dev; + int stat = 0; + int irq_flag = IRQF_SHARED; + + if (pci_enable_device(pdev) < 0) + return -ENODEV; + + dev = vmalloc(sizeof(struct ddb)); + if (dev == NULL) + return -ENOMEM; + memset(dev, 0, sizeof(struct ddb)); + + dev->pdev = pdev; + pci_set_drvdata(pdev, dev); + dev->info = (struct ddb_info *) id->driver_data; + printk(KERN_INFO "DDBridge driver detected: %s\n", dev->info->name); + + dev->regs = ioremap(pci_resource_start(dev->pdev, 0), + pci_resource_len(dev->pdev, 0)); + if (!dev->regs) { + stat = -ENOMEM; + goto fail; + } + printk(KERN_INFO "HW %08x FW %08x\n", ddbreadl(0), ddbreadl(4)); + +#ifdef CONFIG_PCI_MSI + if (pci_msi_enabled()) + stat = pci_enable_msi(dev->pdev); + if (stat) { + printk(KERN_INFO ": MSI not available.\n"); + } else { + irq_flag = 0; + dev->msi = 1; + } +#endif + stat = request_irq(dev->pdev->irq, irq_handler, + irq_flag, "DDBridge", (void *) dev); + if (stat < 0) + goto fail1; + ddbwritel(0, DMA_BASE_WRITE); + ddbwritel(0, DMA_BASE_READ); + ddbwritel(0xffffffff, INTERRUPT_ACK); + ddbwritel(0xfff0f, INTERRUPT_ENABLE); + ddbwritel(0, MSI1_ENABLE); + + if (ddb_i2c_init(dev) < 0) + goto fail1; + ddb_ports_init(dev); + if (ddb_buffers_alloc(dev) < 0) { + printk(KERN_INFO ": Could not allocate buffer memory\n"); + goto fail2; + } + if (ddb_ports_attach(dev) < 0) + goto fail3; + ddb_device_create(dev); + return 0; + +fail3: + ddb_ports_detach(dev); + printk(KERN_ERR "fail3\n"); + ddb_ports_release(dev); +fail2: + printk(KERN_ERR "fail2\n"); + ddb_buffers_free(dev); +fail1: + printk(KERN_ERR "fail1\n"); + if (dev->msi) + pci_disable_msi(dev->pdev); + free_irq(dev->pdev->irq, dev); +fail: + printk(KERN_ERR "fail\n"); + ddb_unmap(dev); + pci_set_drvdata(pdev, 0); + pci_disable_device(pdev); + return -1; +} + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + +static struct ddb_info ddb_none = { + .type = DDB_NONE, + .name = "Digital Devices PCIe bridge", +}; + +static struct ddb_info ddb_octopus = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Octopus DVB adapter", + .port_num = 4, +}; + +static struct ddb_info ddb_octopus_le = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Octopus LE DVB adapter", + .port_num = 2, +}; + +static struct ddb_info ddb_v6 = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Cine S2 V6 DVB adapter", + .port_num = 3, +}; + +#define DDVID 0xdd01 /* Digital Devices Vendor ID */ + +#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) { \ + .vendor = _vend, .device = _dev, \ + .subvendor = _subvend, .subdevice = _subdev, \ + .driver_data = (unsigned long)&_driverdata } + +static const struct pci_device_id ddb_id_tbl[] __devinitdata = { + DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus), + DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus), + DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le), + DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus), + DDB_ID(DDVID, 0x0003, DDVID, 0x0020, ddb_v6), + /* in case sub-ids got deleted in flash */ + DDB_ID(DDVID, 0x0003, PCI_ANY_ID, PCI_ANY_ID, ddb_none), + {0} +}; +MODULE_DEVICE_TABLE(pci, ddb_id_tbl); + + +static struct pci_driver ddb_pci_driver = { + .name = "DDBridge", + .id_table = ddb_id_tbl, + .probe = ddb_probe, + .remove = ddb_remove, +}; + +static __init int module_init_ddbridge(void) +{ + printk(KERN_INFO "Digital Devices PCIE bridge driver, " + "Copyright (C) 2010-11 Digital Devices GmbH\n"); + if (ddb_class_create()) + return -1; + return pci_register_driver(&ddb_pci_driver); +} + +static __exit void module_exit_ddbridge(void) +{ + pci_unregister_driver(&ddb_pci_driver); + ddb_class_destroy(); +} + +module_init(module_init_ddbridge); +module_exit(module_exit_ddbridge); + +MODULE_DESCRIPTION("Digital Devices PCIe Bridge"); +MODULE_AUTHOR("Ralph Metzler"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.5"); diff --git a/drivers/media/dvb/ddbridge/ddbridge-regs.h b/drivers/media/dvb/ddbridge/ddbridge-regs.h new file mode 100644 index 0000000000000000000000000000000000000000..a3ccb318b500055b4506707e5b19aed74a511e76 --- /dev/null +++ b/drivers/media/dvb/ddbridge/ddbridge-regs.h @@ -0,0 +1,151 @@ +/* + * ddbridge-regs.h: Digital Devices PCIe bridge driver + * + * Copyright (C) 2010-2011 Digital Devices GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +/* DD-DVBBridgeV1.h 273 2010-09-17 05:03:16Z manfred */ + +/* Register Definitions */ + +#define CUR_REGISTERMAP_VERSION 0x10000 + +#define HARDWARE_VERSION 0x00 +#define REGISTERMAP_VERSION 0x04 + +/* ------------------------------------------------------------------------- */ +/* SPI Controller */ + +#define SPI_CONTROL 0x10 +#define SPI_DATA 0x14 + +/* ------------------------------------------------------------------------- */ + +/* Interrupt controller */ +/* How many MSI's are available depends on HW (Min 2 max 8) */ +/* How many are usable also depends on Host platform */ + +#define INTERRUPT_BASE (0x40) + +#define INTERRUPT_ENABLE (INTERRUPT_BASE + 0x00) +#define MSI0_ENABLE (INTERRUPT_BASE + 0x00) +#define MSI1_ENABLE (INTERRUPT_BASE + 0x04) +#define MSI2_ENABLE (INTERRUPT_BASE + 0x08) +#define MSI3_ENABLE (INTERRUPT_BASE + 0x0C) +#define MSI4_ENABLE (INTERRUPT_BASE + 0x10) +#define MSI5_ENABLE (INTERRUPT_BASE + 0x14) +#define MSI6_ENABLE (INTERRUPT_BASE + 0x18) +#define MSI7_ENABLE (INTERRUPT_BASE + 0x1C) + +#define INTERRUPT_STATUS (INTERRUPT_BASE + 0x20) +#define INTERRUPT_ACK (INTERRUPT_BASE + 0x20) + +#define INTMASK_I2C1 (0x00000001) +#define INTMASK_I2C2 (0x00000002) +#define INTMASK_I2C3 (0x00000004) +#define INTMASK_I2C4 (0x00000008) + +#define INTMASK_CIRQ1 (0x00000010) +#define INTMASK_CIRQ2 (0x00000020) +#define INTMASK_CIRQ3 (0x00000040) +#define INTMASK_CIRQ4 (0x00000080) + +#define INTMASK_TSINPUT1 (0x00000100) +#define INTMASK_TSINPUT2 (0x00000200) +#define INTMASK_TSINPUT3 (0x00000400) +#define INTMASK_TSINPUT4 (0x00000800) +#define INTMASK_TSINPUT5 (0x00001000) +#define INTMASK_TSINPUT6 (0x00002000) +#define INTMASK_TSINPUT7 (0x00004000) +#define INTMASK_TSINPUT8 (0x00008000) + +#define INTMASK_TSOUTPUT1 (0x00010000) +#define INTMASK_TSOUTPUT2 (0x00020000) +#define INTMASK_TSOUTPUT3 (0x00040000) +#define INTMASK_TSOUTPUT4 (0x00080000) + +/* ------------------------------------------------------------------------- */ +/* I2C Master Controller */ + +#define I2C_BASE (0x80) /* Byte offset */ + +#define I2C_COMMAND (0x00) +#define I2C_TIMING (0x04) +#define I2C_TASKLENGTH (0x08) /* High read, low write */ +#define I2C_TASKADDRESS (0x0C) /* High read, low write */ + +#define I2C_MONITOR (0x1C) + +#define I2C_BASE_1 (I2C_BASE + 0x00) +#define I2C_BASE_2 (I2C_BASE + 0x20) +#define I2C_BASE_3 (I2C_BASE + 0x40) +#define I2C_BASE_4 (I2C_BASE + 0x60) + +#define I2C_BASE_N(i) (I2C_BASE + (i) * 0x20) + +#define I2C_TASKMEM_BASE (0x1000) /* Byte offset */ +#define I2C_TASKMEM_SIZE (0x1000) + +#define I2C_SPEED_400 (0x04030404) +#define I2C_SPEED_200 (0x09080909) +#define I2C_SPEED_154 (0x0C0B0C0C) +#define I2C_SPEED_100 (0x13121313) +#define I2C_SPEED_77 (0x19181919) +#define I2C_SPEED_50 (0x27262727) + + +/* ------------------------------------------------------------------------- */ +/* DMA Controller */ + +#define DMA_BASE_WRITE (0x100) +#define DMA_BASE_READ (0x140) + +#define DMA_CONTROL (0x00) /* 64 */ +#define DMA_ERROR (0x04) /* 65 ( only read instance ) */ + +#define DMA_DIAG_CONTROL (0x1C) /* 71 */ +#define DMA_DIAG_PACKETCOUNTER_LOW (0x20) /* 72 */ +#define DMA_DIAG_PACKETCOUNTER_HIGH (0x24) /* 73 */ +#define DMA_DIAG_TIMECOUNTER_LOW (0x28) /* 74 */ +#define DMA_DIAG_TIMECOUNTER_HIGH (0x2C) /* 75 */ +#define DMA_DIAG_RECHECKCOUNTER (0x30) /* 76 ( Split completions on read ) */ +#define DMA_DIAG_WAITTIMEOUTINIT (0x34) /* 77 */ +#define DMA_DIAG_WAITOVERFLOWCOUNTER (0x38) /* 78 */ +#define DMA_DIAG_WAITCOUNTER (0x3C) /* 79 */ + +/* ------------------------------------------------------------------------- */ +/* DMA Buffer */ + +#define TS_INPUT_BASE (0x200) +#define TS_INPUT_CONTROL(i) (TS_INPUT_BASE + (i) * 16 + 0x00) + +#define TS_OUTPUT_BASE (0x280) +#define TS_OUTPUT_CONTROL(i) (TS_OUTPUT_BASE + (i) * 16 + 0x00) + +#define DMA_BUFFER_BASE (0x300) + +#define DMA_BUFFER_CONTROL(i) (DMA_BUFFER_BASE + (i) * 16 + 0x00) +#define DMA_BUFFER_ACK(i) (DMA_BUFFER_BASE + (i) * 16 + 0x04) +#define DMA_BUFFER_CURRENT(i) (DMA_BUFFER_BASE + (i) * 16 + 0x08) +#define DMA_BUFFER_SIZE(i) (DMA_BUFFER_BASE + (i) * 16 + 0x0c) + +#define DMA_BASE_ADDRESS_TABLE (0x2000) +#define DMA_BASE_ADDRESS_TABLE_ENTRIES (512) + diff --git a/drivers/media/dvb/ddbridge/ddbridge.h b/drivers/media/dvb/ddbridge/ddbridge.h new file mode 100644 index 0000000000000000000000000000000000000000..6d14893218f432af9a433ce3b3699e5b0739dfa2 --- /dev/null +++ b/drivers/media/dvb/ddbridge/ddbridge.h @@ -0,0 +1,187 @@ +/* + * ddbridge.h: Digital Devices PCIe bridge driver + * + * Copyright (C) 2010-2011 Digital Devices GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef _DDBRIDGE_H_ +#define _DDBRIDGE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_ringbuffer.h" +#include "dvb_ca_en50221.h" +#include "dvb_net.h" +#include "cxd2099.h" + +#define DDB_MAX_I2C 4 +#define DDB_MAX_PORT 4 +#define DDB_MAX_INPUT 8 +#define DDB_MAX_OUTPUT 4 + +struct ddb_info { + int type; +#define DDB_NONE 0 +#define DDB_OCTOPUS 1 + char *name; + int port_num; + u32 port_type[DDB_MAX_PORT]; +}; + +/* DMA_SIZE MUST be divisible by 188 and 128 !!! */ + +#define INPUT_DMA_MAX_BUFS 32 /* hardware table limit */ +#define INPUT_DMA_BUFS 8 +#define INPUT_DMA_SIZE (128*47*21) + +#define OUTPUT_DMA_MAX_BUFS 32 +#define OUTPUT_DMA_BUFS 8 +#define OUTPUT_DMA_SIZE (128*47*21) + +struct ddb; +struct ddb_port; + +struct ddb_input { + struct ddb_port *port; + u32 nr; + int attached; + + dma_addr_t pbuf[INPUT_DMA_MAX_BUFS]; + u8 *vbuf[INPUT_DMA_MAX_BUFS]; + u32 dma_buf_num; + u32 dma_buf_size; + + struct tasklet_struct tasklet; + spinlock_t lock; + wait_queue_head_t wq; + int running; + u32 stat; + u32 cbuf; + u32 coff; + + struct dvb_adapter adap; + struct dvb_device *dev; + struct dvb_frontend *fe; + struct dvb_frontend *fe2; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dvb_net dvbnet; + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + int users; + int (*gate_ctrl)(struct dvb_frontend *, int); +}; + +struct ddb_output { + struct ddb_port *port; + u32 nr; + dma_addr_t pbuf[OUTPUT_DMA_MAX_BUFS]; + u8 *vbuf[OUTPUT_DMA_MAX_BUFS]; + u32 dma_buf_num; + u32 dma_buf_size; + struct tasklet_struct tasklet; + spinlock_t lock; + wait_queue_head_t wq; + int running; + u32 stat; + u32 cbuf; + u32 coff; + + struct dvb_adapter adap; + struct dvb_device *dev; +}; + +struct ddb_i2c { + struct ddb *dev; + u32 nr; + struct i2c_adapter adap; + struct i2c_adapter adap2; + u32 regs; + u32 rbuf; + u32 wbuf; + int done; + wait_queue_head_t wq; +}; + +struct ddb_port { + struct ddb *dev; + u32 nr; + struct ddb_i2c *i2c; + struct mutex i2c_gate_lock; + u32 class; +#define DDB_PORT_NONE 0 +#define DDB_PORT_CI 1 +#define DDB_PORT_TUNER 2 + u32 type; +#define DDB_TUNER_NONE 0 +#define DDB_TUNER_DVBS_ST 1 +#define DDB_TUNER_DVBS_ST_AA 2 +#define DDB_TUNER_DVBCT_TR 16 +#define DDB_TUNER_DVBCT_ST 17 + u32 adr; + + struct ddb_input *input[2]; + struct ddb_output *output; + struct dvb_ca_en50221 *en; +}; + +struct ddb { + struct pci_dev *pdev; + unsigned char *regs; + struct ddb_port port[DDB_MAX_PORT]; + struct ddb_i2c i2c[DDB_MAX_I2C]; + struct ddb_input input[DDB_MAX_INPUT]; + struct ddb_output output[DDB_MAX_OUTPUT]; + + struct device *ddb_dev; + int nr; + u8 iobuf[1028]; + + struct ddb_info *info; + int msi; +}; + +/****************************************************************************/ + +#define ddbwritel(_val, _adr) writel((_val), \ + (char *) (dev->regs+(_adr))) +#define ddbreadl(_adr) readl((char *) (dev->regs+(_adr))) +#define ddbcpyto(_adr, _src, _count) memcpy_toio((char *) \ + (dev->regs+(_adr)), (_src), (_count)) +#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), (char *) \ + (dev->regs+(_adr)), (_count)) + +/****************************************************************************/ + +#endif diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile index 0b5182835cc82d4205b06ac473073d3e1b6e0ac2..8f22bcd7c1f9122694e552cb1c39688ee95b1518 100644 --- a/drivers/media/dvb/dvb-core/Makefile +++ b/drivers/media/dvb/dvb-core/Makefile @@ -2,8 +2,10 @@ # Makefile for the kernel DVB device drivers. # +dvb-net-$(CONFIG_DVB_NET) := dvb_net.o + dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ dvb_ca_en50221.o dvb_frontend.o \ - dvb_net.o dvb_ringbuffer.o dvb_math.o + $(dvb-net-y) dvb_ringbuffer.o dvb_math.o obj-$(CONFIG_DVB_CORE) += dvb-core.o diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 5b6b451d46940db41b8d2b3fd4473e7a1429383a..efe9c30605e890688b6a7557156436fe0c4611a9 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -904,7 +904,7 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) .buffer = b \ } -static struct dtv_cmds_h dtv_cmds[] = { +static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_TUNE, 1, 0), _DTV_CMD(DTV_CLEAR, 1, 0), @@ -966,6 +966,7 @@ static struct dtv_cmds_h dtv_cmds[] = { _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0, 0), _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0), + _DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0), /* Get */ _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1), diff --git a/drivers/media/dvb/dvb-core/dvb_net.h b/drivers/media/dvb/dvb-core/dvb_net.h index 3a3126cae03b0c26d81b1f639017a1c87b0554c4..1e53acd50cf40fa22d2e15f7d1932aadcbb03df7 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.h +++ b/drivers/media/dvb/dvb-core/dvb_net.h @@ -32,6 +32,8 @@ #define DVB_NET_DEVICES_MAX 10 +#ifdef CONFIG_DVB_NET + struct dvb_net { struct dvb_device *dvbdev; struct net_device *device[DVB_NET_DEVICES_MAX]; @@ -40,8 +42,25 @@ struct dvb_net { struct dmx_demux *demux; }; - void dvb_net_release(struct dvb_net *); int dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *); +#else + +struct dvb_net { + struct dvb_device *dvbdev; +}; + +static inline void dvb_net_release(struct dvb_net *dvbnet) +{ +} + +static inline int dvb_net_init(struct dvb_adapter *adap, + struct dvb_net *dvbnet, struct dmx_demux *dmx) +{ + return 0; +} + +#endif /* ifdef CONFIG_DVB_NET */ + #endif diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index e85304c59a2bcea78273f4b316d241aa6c49152c..5d73dec8ac0724a557a8ba8a223e8edc0c9e2651 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -81,6 +81,7 @@ config DVB_USB_DIB0700 select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 100ebc37e99e2293699816a15556fdc672640e05..d7ad05fc383b7a8422fb8d1b8425bb87862790ed 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -91,7 +91,6 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) case GET_CONFIG: case READ_MEMORY: case RECONNECT_USB: - case GET_IR_CODE: write = 0; break; case READ_I2C: @@ -164,13 +163,6 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) deb_xfer("<<< "); debug_dump(buf, act_len, deb_xfer); - /* remote controller query status is 1 if remote code is not received */ - if (req->cmd == GET_IR_CODE && buf[1] == 1) { - buf[1] = 0; /* clear command "error" status */ - memset(&buf[2], 0, req->data_len); - buf[3] = 1; /* no remote code received mark */ - } - /* check status */ if (buf[1]) { err("command failed:%d", buf[1]); @@ -292,6 +284,10 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. } if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].len > 3 || msg[i+1].len > 61) { + ret = -EOPNOTSUPP; + goto error; + } if (msg[i].addr == af9015_af9013_config[0].demod_address) req.cmd = READ_MEMORY; @@ -306,12 +302,16 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = af9015_ctrl_msg(d, &req); i += 2; } else if (msg[i].flags & I2C_M_RD) { - ret = -EINVAL; + if (msg[i].len > 61) { + ret = -EOPNOTSUPP; + goto error; + } if (msg[i].addr == - af9015_af9013_config[0].demod_address) + af9015_af9013_config[0].demod_address) { + ret = -EINVAL; goto error; - else - req.cmd = READ_I2C; + } + req.cmd = READ_I2C; req.i2c_addr = msg[i].addr; req.addr = addr; req.mbox = mbox; @@ -321,6 +321,10 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = af9015_ctrl_msg(d, &req); i += 1; } else { + if (msg[i].len > 21) { + ret = -EOPNOTSUPP; + goto error; + } if (msg[i].addr == af9015_af9013_config[0].demod_address) req.cmd = WRITE_MEMORY; @@ -735,6 +739,7 @@ static const struct af9015_rc_setup af9015_rc_setup_hashes[] = { { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II }, { 0xa3703d00, RC_MAP_ALINK_DTU_M }, { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */ + { 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */ { } }; @@ -749,6 +754,8 @@ static const struct af9015_rc_setup af9015_rc_setup_usbids[] = { RC_MAP_AZUREWAVE_AD_TU700 }, { (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGI_VOX_MINI_III, RC_MAP_MSI_DIGIVOX_III }, + { (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGIVOX_DUO, + RC_MAP_MSI_DIGIVOX_III }, { (USB_VID_LEADTEK << 16) + USB_PID_WINFAST_DTV_DONGLE_GOLD, RC_MAP_LEADTEK_Y04G0051 }, { (USB_VID_AVERMEDIA << 16) + USB_PID_AVERMEDIA_VOLAR_X, @@ -759,6 +766,8 @@ static const struct af9015_rc_setup af9015_rc_setup_usbids[] = { RC_MAP_DIGITALNOW_TINYTWIN }, { (USB_VID_GTEK << 16) + USB_PID_TINYTWIN_3, RC_MAP_DIGITALNOW_TINYTWIN }, + { (USB_VID_KWORLD_2 << 16) + USB_PID_SVEON_STV22, + RC_MAP_MSI_DIGIVOX_III }, { } }; @@ -1082,44 +1091,11 @@ static int af9015_rc_query(struct dvb_usb_device *d) return ret; } -/* init 2nd I2C adapter */ -static int af9015_i2c_init(struct dvb_usb_device *d) -{ - int ret; - struct af9015_state *state = d->priv; - deb_info("%s:\n", __func__); - - strncpy(state->i2c_adap.name, d->desc->name, - sizeof(state->i2c_adap.name)); - state->i2c_adap.algo = d->props.i2c_algo; - state->i2c_adap.algo_data = NULL; - state->i2c_adap.dev.parent = &d->udev->dev; - - i2c_set_adapdata(&state->i2c_adap, d); - - ret = i2c_add_adapter(&state->i2c_adap); - if (ret < 0) - err("could not add i2c adapter"); - - return ret; -} - static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) { int ret; - struct af9015_state *state = adap->dev->priv; - struct i2c_adapter *i2c_adap; - - if (adap->id == 0) { - /* select I2C adapter */ - i2c_adap = &adap->dev->i2c_adap; - - deb_info("%s: init I2C\n", __func__); - ret = af9015_i2c_init(adap->dev); - } else { - /* select I2C adapter */ - i2c_adap = &state->i2c_adap; + if (adap->id == 1) { /* copy firmware to 2nd demodulator */ if (af9015_config.dual_mode) { ret = af9015_copy_firmware(adap->dev); @@ -1136,7 +1112,7 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) /* attach demodulator */ adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id], - i2c_adap); + &adap->dev->i2c_adap); return adap->fe == NULL ? -ENODEV : 0; } @@ -1206,57 +1182,56 @@ static struct mxl5007t_config af9015_mxl5007t_config = { static int af9015_tuner_attach(struct dvb_usb_adapter *adap) { - struct af9015_state *state = adap->dev->priv; - struct i2c_adapter *i2c_adap; int ret; deb_info("%s:\n", __func__); - /* select I2C adapter */ - if (adap->id == 0) - i2c_adap = &adap->dev->i2c_adap; - else - i2c_adap = &state->i2c_adap; - switch (af9015_af9013_config[adap->id].tuner) { case AF9013_TUNER_MT2060: case AF9013_TUNER_MT2060_2: - ret = dvb_attach(mt2060_attach, adap->fe, i2c_adap, + ret = dvb_attach(mt2060_attach, adap->fe, &adap->dev->i2c_adap, &af9015_mt2060_config, af9015_config.mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_QT1010: case AF9013_TUNER_QT1010A: - ret = dvb_attach(qt1010_attach, adap->fe, i2c_adap, + ret = dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap, &af9015_qt1010_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18271: - ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, i2c_adap, + ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, + &adap->dev->i2c_adap, &af9015_tda18271_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18218: - ret = dvb_attach(tda18218_attach, adap->fe, i2c_adap, + ret = dvb_attach(tda18218_attach, adap->fe, + &adap->dev->i2c_adap, &af9015_tda18218_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5003D: - ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap, + ret = dvb_attach(mxl5005s_attach, adap->fe, + &adap->dev->i2c_adap, &af9015_mxl5003_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: - ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap, + ret = dvb_attach(mxl5005s_attach, adap->fe, + &adap->dev->i2c_adap, &af9015_mxl5005_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_ENV77H11D5: - ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0, i2c_adap, + ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0, + &adap->dev->i2c_adap, DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MC44S803: - ret = dvb_attach(mc44s803_attach, adap->fe, i2c_adap, + ret = dvb_attach(mc44s803_attach, adap->fe, + &adap->dev->i2c_adap, &af9015_mc44s803_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5007T: - ret = dvb_attach(mxl5007t_attach, adap->fe, i2c_adap, + ret = dvb_attach(mxl5007t_attach, adap->fe, + &adap->dev->i2c_adap, 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_UNKNOWN: @@ -1309,6 +1284,7 @@ static struct usb_device_id af9015_usb_table[] = { USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)}, /* 35 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)}, {USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22)}, {0}, }; MODULE_DEVICE_TABLE(usb, af9015_usb_table); @@ -1502,7 +1478,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { .i2c_algo = &af9015_i2c_algo, - .num_device_descs = 9, /* check max from dvb-usb.h */ + .num_device_descs = 10, /* check max from dvb-usb.h */ .devices = { { .name = "Xtensions XD-380", @@ -1554,6 +1530,11 @@ static struct dvb_usb_device_properties af9015_properties[] = { .cold_ids = {&af9015_usb_table[20], NULL}, .warm_ids = {NULL}, }, + { + .name = "Sveon STV22 Dual USB DVB-T Tuner HDTV", + .cold_ids = {&af9015_usb_table[37], NULL}, + .warm_ids = {NULL}, + }, } }, { .caps = DVB_USB_IS_AN_I2C_ADAPTER, @@ -1704,33 +1685,11 @@ static int af9015_usb_probe(struct usb_interface *intf, return ret; } -static void af9015_i2c_exit(struct dvb_usb_device *d) -{ - struct af9015_state *state = d->priv; - deb_info("%s:\n", __func__); - - /* remove 2nd I2C adapter */ - if (d->state & DVB_USB_STATE_I2C) - i2c_del_adapter(&state->i2c_adap); -} - -static void af9015_usb_device_exit(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - deb_info("%s:\n", __func__); - - /* remove 2nd I2C adapter */ - if (d != NULL && d->desc != NULL) - af9015_i2c_exit(d); - - dvb_usb_device_exit(intf); -} - /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver af9015_usb_driver = { .name = "dvb_usb_af9015", .probe = af9015_usb_probe, - .disconnect = af9015_usb_device_exit, + .disconnect = dvb_usb_device_exit, .id_table = af9015_usb_table, }; diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h index beb3004f00ba31640aab86399fd7ef4889469d14..6252ea6c19042b75a92e6aee88b3d9ec258f24da 100644 --- a/drivers/media/dvb/dvb-usb/af9015.h +++ b/drivers/media/dvb/dvb-usb/af9015.h @@ -99,7 +99,6 @@ enum af9015_ir_mode { }; struct af9015_state { - struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */ u8 rc_repeat; u32 rc_keycode; u8 rc_last[4]; diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index 7c327b54308e30312848d7b9c4c289f28fe2d937..2cbf19a52e38d5124be4b7f805e70f4ce6e8d62f 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -347,15 +347,17 @@ static struct isl6423_config anysee_isl6423_config = { * PCB: ? * parts: DNOS404ZH102A(MT352, DTT7579(?)) * - * E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=???????? - * PCB: ? + * E30 VID=04b4 PID=861f HW=2 FW=2.1 "anysee-T(LP)" + * PCB: PCB 507T (rev1.61) * parts: DNOS404ZH103A(ZL10353, DTT7579(?)) + * OEA=0a OEB=00 OEC=00 OED=ff OEE=00 + * IOA=45 IOB=ff IOC=00 IOD=ff IOE=00 * * E30 Plus VID=04b4 PID=861f HW=6 FW=1.0 "anysee" * PCB: 507CD (rev1.1) * parts: DNOS404ZH103A(ZL10353, DTT7579(?)), CST56I01 - * OEA=80 OEB=00 OEC=00 OED=ff OEF=fe - * IOA=4f IOB=ff IOC=00 IOD=06 IOF=01 + * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe + * IOA=4f IOB=ff IOC=00 IOD=06 IOE=01 * IOD[0] ZL10353 1=enabled * IOA[7] TS 0=enabled * tuner is not behind ZL10353 I2C-gate (no care if gate disabled or not) @@ -363,30 +365,30 @@ static struct isl6423_config anysee_isl6423_config = { * E30 C Plus VID=04b4 PID=861f HW=10 FW=1.0 "anysee-DC(LP)" * PCB: 507DC (rev0.2) * parts: TDA10023, DTOS403IH102B TM, CST56I01 - * OEA=80 OEB=00 OEC=00 OED=ff OEF=fe - * IOA=4f IOB=ff IOC=00 IOD=26 IOF=01 + * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe + * IOA=4f IOB=ff IOC=00 IOD=26 IOE=01 * IOD[0] TDA10023 1=enabled * * E30 S2 Plus VID=04b4 PID=861f HW=11 FW=0.1 "anysee-S2(LP)" * PCB: 507SI (rev2.1) * parts: BS2N10WCC01(CX24116, CX24118), ISL6423, TDA8024 - * OEA=80 OEB=00 OEC=ff OED=ff OEF=fe - * IOA=4d IOB=ff IOC=00 IOD=26 IOF=01 + * OEA=80 OEB=00 OEC=ff OED=ff OEE=fe + * IOA=4d IOB=ff IOC=00 IOD=26 IOE=01 * IOD[0] CX24116 1=enabled * * E30 C Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)" * PCB: 507FA (rev0.4) * parts: TDA10023, DTOS403IH102B TM, TDA8024 - * OEA=80 OEB=00 OEC=ff OED=ff OEF=ff - * IOA=4d IOB=ff IOC=00 IOD=00 IOF=c0 + * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff + * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0 * IOD[5] TDA10023 1=enabled * IOE[0] tuner 1=enabled * * E30 Combo Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)" * PCB: 507FA (rev1.1) * parts: ZL10353, TDA10023, DTOS403IH102B TM, TDA8024 - * OEA=80 OEB=00 OEC=ff OED=ff OEF=ff - * IOA=4d IOB=ff IOC=00 IOD=00 IOF=c0 + * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff + * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0 * DVB-C: * IOD[5] TDA10023 1=enabled * IOE[0] tuner 1=enabled @@ -398,8 +400,8 @@ static struct isl6423_config anysee_isl6423_config = { * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)" * PCB: 508TC (rev0.6) * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212) - * OEA=80 OEB=00 OEC=03 OED=f7 OEF=ff - * IOA=4d IOB=00 IOC=cc IOD=48 IOF=e4 + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 * IOA[7] TS 1=enabled * IOE[4] TDA18212 1=enabled * DVB-C: @@ -414,11 +416,34 @@ static struct isl6423_config anysee_isl6423_config = { * E7 S2 VID=1c73 PID=861f HW=19 FW=0.4 AMTCI=0.5 "anysee-E7S2(LP)" * PCB: 508S2 (rev0.7) * parts: DNBU10512IST(STV0903, STV6110), ISL6423 - * OEA=80 OEB=00 OEC=03 OED=f7 OEF=ff - * IOA=4d IOB=00 IOC=c4 IOD=08 IOF=e4 + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4 * IOA[7] TS 1=enabled * IOE[5] STV0903 1=enabled * + * E7 PTC VID=1c73 PID=861f HW=21 FW=0.1 AMTCI=?? "anysee-E7PTC(LP)" + * PCB: 508PTC (rev0.5) + * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212) + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[4] TDA18212 1=enabled + * DVB-C: + * IOD[6] ZL10353 0=disabled + * IOD[5] TDA10023 1=enabled + * IOE[0] IF 1=enabled + * DVB-T: + * IOD[5] TDA10023 0=disabled + * IOD[6] ZL10353 1=enabled + * IOE[0] IF 0=enabled + * + * E7 S2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)" + * PCB: 508PS2 (rev0.4) + * parts: DNBU10512IST(STV0903, STV6110), ISL6423 + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[5] STV0903 1=enabled */ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) @@ -459,7 +484,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) state->hw = hw_info[0]; switch (state->hw) { - case ANYSEE_HW_02: /* 2 */ + case ANYSEE_HW_507T: /* 2 */ /* E30 */ /* attach demod */ @@ -593,7 +618,9 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) break; case ANYSEE_HW_508TC: /* 18 */ + case ANYSEE_HW_508PTC: /* 21 */ /* E7 TC */ + /* E7 PTC */ /* enable transport stream on IOA[7] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80); @@ -650,7 +677,9 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) break; case ANYSEE_HW_508S2: /* 19 */ + case ANYSEE_HW_508PS2: /* 22 */ /* E7 S2 */ + /* E7 PS2 */ /* enable transport stream on IOA[7] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80); @@ -687,7 +716,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) deb_info("%s:\n", __func__); switch (state->hw) { - case ANYSEE_HW_02: /* 2 */ + case ANYSEE_HW_507T: /* 2 */ /* E30 */ /* attach tuner */ @@ -762,7 +791,9 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) break; case ANYSEE_HW_508TC: /* 18 */ + case ANYSEE_HW_508PTC: /* 21 */ /* E7 TC */ + /* E7 PTC */ /* enable tuner on IOE[4] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10); @@ -775,7 +806,9 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) break; case ANYSEE_HW_508S2: /* 19 */ + case ANYSEE_HW_508PS2: /* 22 */ /* E7 S2 */ + /* E7 PS2 */ /* attach tuner */ fe = dvb_attach(stv6110_attach, adap->fe, diff --git a/drivers/media/dvb/dvb-usb/anysee.h b/drivers/media/dvb/dvb-usb/anysee.h index a7673aa1e007810627876ad9702ec4662607c003..ad6ccd1ea2d9bdabe67a3a88e7e22262db72e425 100644 --- a/drivers/media/dvb/dvb-usb/anysee.h +++ b/drivers/media/dvb/dvb-usb/anysee.h @@ -61,13 +61,15 @@ struct anysee_state { u8 seq; }; -#define ANYSEE_HW_02 2 /* E30 */ -#define ANYSEE_HW_507CD 6 /* E30 Plus */ -#define ANYSEE_HW_507DC 10 /* E30 C Plus */ -#define ANYSEE_HW_507SI 11 /* E30 S2 Plus */ -#define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */ -#define ANYSEE_HW_508TC 18 /* E7 TC */ -#define ANYSEE_HW_508S2 19 /* E7 S2 */ +#define ANYSEE_HW_507T 2 /* E30 */ +#define ANYSEE_HW_507CD 6 /* E30 Plus */ +#define ANYSEE_HW_507DC 10 /* E30 C Plus */ +#define ANYSEE_HW_507SI 11 /* E30 S2 Plus */ +#define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */ +#define ANYSEE_HW_508TC 18 /* E7 TC */ +#define ANYSEE_HW_508S2 19 /* E7 S2 */ +#define ANYSEE_HW_508PTC 21 /* E7 PTC Plus */ +#define ANYSEE_HW_508PS2 22 /* E7 PS2 Plus */ #define REG_IOA 0x80 /* Port A (bit addressable) */ #define REG_IOB 0x90 /* Port B (bit addressable) */ diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index c519ad5eb731f4672b7d4ff65ab9ea40777ecafc..d0ea5b64f6b4e10f6e028b99915d3100c94d61a3 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -17,6 +17,7 @@ #include "mt2266.h" #include "tuner-xc2028.h" #include "xc5000.h" +#include "xc4000.h" #include "s5h1411.h" #include "dib0070.h" #include "dib0090.h" @@ -2655,6 +2656,156 @@ static int xc5000_tuner_attach(struct dvb_usb_adapter *adap) == NULL ? -ENODEV : 0; } +static int dib0700_xc4000_tuner_callback(void *priv, int component, + int command, int arg) +{ + struct dvb_usb_adapter *adap = priv; + + if (command == XC4000_TUNER_RESET) { + /* Reset the tuner */ + dib7000p_set_gpio(adap->fe, 8, 0, 0); + msleep(10); + dib7000p_set_gpio(adap->fe, 8, 0, 1); + } else { + err("xc4000: unknown tuner callback command: %d\n", command); + return -EINVAL; + } + + return 0; +} + +static struct dibx000_agc_config stk7700p_7000p_xc4000_agc_config = { + .band_caps = BAND_UHF | BAND_VHF, + .setup = 0x64, + .inv_gain = 0x02c8, + .time_stabiliz = 0x15, + .alpha_level = 0x00, + .thlock = 0x76, + .wbd_inv = 0x01, + .wbd_ref = 0x0b33, + .wbd_sel = 0x00, + .wbd_alpha = 0x02, + .agc1_max = 0x00, + .agc1_min = 0x00, + .agc2_max = 0x9b26, + .agc2_min = 0x26ca, + .agc1_pt1 = 0x00, + .agc1_pt2 = 0x00, + .agc1_pt3 = 0x00, + .agc1_slope1 = 0x00, + .agc1_slope2 = 0x00, + .agc2_pt1 = 0x00, + .agc2_pt2 = 0x80, + .agc2_slope1 = 0x1d, + .agc2_slope2 = 0x1d, + .alpha_mant = 0x11, + .alpha_exp = 0x1b, + .beta_mant = 0x17, + .beta_exp = 0x33, + .perform_agc_softsplit = 0x00, +}; + +static struct dibx000_bandwidth_config stk7700p_xc4000_pll_config = { + 60000, 30000, /* internal, sampling */ + 1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */ + 0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, */ + /* ADClkSrc, modulo */ + (3 << 14) | (1 << 12) | 524, /* sad_cfg: refsel, sel, freq_15k */ + 39370534, /* ifreq */ + 20452225, /* timf */ + 30000000 /* xtal */ +}; + +/* FIXME: none of these inputs are validated yet */ +static struct dib7000p_config pctv_340e_config = { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &stk7700p_7000p_xc4000_agc_config, + .bw = &stk7700p_xc4000_pll_config, + + .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, +}; + +/* PCTV 340e GPIOs map: + dib0700: + GPIO2 - CX25843 sleep + GPIO3 - CS5340 reset + GPIO5 - IRD + GPIO6 - Power Supply + GPIO8 - LNA (1=off 0=on) + GPIO10 - CX25843 reset + dib7000: + GPIO8 - xc4000 reset + */ +static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + + /* Power Supply on */ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + msleep(50); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(100); /* Allow power supply to settle before probing */ + + /* cx25843 reset */ + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(1); /* cx25843 datasheet say 350us required */ + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + + /* LNA off for now */ + dib0700_set_gpio(adap->dev, GPIO8, GPIO_OUT, 1); + + /* Put the CX25843 to sleep for now since we're in digital mode */ + dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1); + + /* FIXME: not verified yet */ + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(500); + + if (dib7000pc_detection(&adap->dev->i2c_adap) == 0) { + /* Demodulator not found for some reason? */ + return -ENODEV; + } + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12, + &pctv_340e_config); + st->is_dib7000pc = 1; + + return adap->fe == NULL ? -ENODEV : 0; +} + +static struct xc4000_config dib7000p_xc4000_tunerconfig = { + .i2c_address = 0x61, + .default_pm = 1, + .dvb_amplitude = 0, + .set_smoothedcvbs = 0, + .if_khz = 5400 +}; + +static int xc4000_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *tun_i2c; + + /* The xc4000 is not on the main i2c bus */ + tun_i2c = dib7000p_get_i2c_master(adap->fe, + DIBX000_I2C_INTERFACE_TUNER, 1); + if (tun_i2c == NULL) { + printk(KERN_ERR "Could not reach tuner i2c bus\n"); + return 0; + } + + /* Setup the reset callback */ + adap->fe->callback = dib0700_xc4000_tuner_callback; + + return dvb_attach(xc4000_attach, adap->fe, tun_i2c, + &dib7000p_xc4000_tunerconfig) + == NULL ? -ENODEV : 0; +} + static struct lgdt3305_config hcw_lgdt3305_config = { .i2c_addr = 0x0e, .mpeg_mode = LGDT3305_MPEG_PARALLEL, @@ -2802,6 +2953,8 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090PVR) }, { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2) }, /* 75 */{ USB_DEVICE(USB_VID_MEDION, USB_PID_CREATIX_CTX1921) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E_SE) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -3762,6 +3915,41 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .frontend_attach = pctv340e_frontend_attach, + .tuner_attach = xc4000_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct + dib0700_adapter_state), + }, + }, + + .num_device_descs = 2, + .devices = { + { "Pinnacle PCTV 340e HD Pro USB Stick", + { &dib0700_usb_id_table[76], NULL }, + { NULL }, + }, + { "Pinnacle PCTV Hybrid Stick Solo", + { &dib0700_usb_id_table[77], NULL }, + { NULL }, + }, + }, .rc.core = { .rc_interval = DEFAULT_RC_INTERVAL, .rc_codes = RC_MAP_DIB0700_RC5_TABLE, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 21b15495d2d7c588f4acb04875303c88fea196f1..2a79b8fb3e8dc283ddb8ee8a466b9696440eb620 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -230,6 +230,8 @@ #define USB_PID_PINNACLE_PCTV310E 0x3211 #define USB_PID_PINNACLE_PCTV801E 0x023a #define USB_PID_PINNACLE_PCTV801E_SE 0x023b +#define USB_PID_PINNACLE_PCTV340E 0x023d +#define USB_PID_PINNACLE_PCTV340E_SE 0x023e #define USB_PID_PINNACLE_PCTV73A 0x0243 #define USB_PID_PINNACLE_PCTV73ESE 0x0245 #define USB_PID_PINNACLE_PCTV74E 0x0246 @@ -313,6 +315,7 @@ #define USB_PID_FRIIO_WHITE 0x0001 #define USB_PID_TVWAY_PLUS 0x0002 #define USB_PID_SVEON_STV20 0xe39d +#define USB_PID_SVEON_STV22 0xe401 #define USB_PID_AZUREWAVE_AZ6027 0x3275 #define USB_PID_TERRATEC_DVBS2CI_V1 0x10a4 #define USB_PID_TERRATEC_DVBS2CI_V2 0x10ac diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 76a80968482a602033cfead87ddd029301a832d2..7d35d078342b41522443868a2436fadc550ad92c 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -85,7 +85,7 @@ static inline u8 rc5_data(struct rc_map_table *key) return key->scancode & 0xff; } -static inline u8 rc5_scan(struct rc_map_table *key) +static inline u16 rc5_scan(struct rc_map_table *key) { return key->scancode & 0xffff; } diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h index 831749a518cbed7dbf05700fa890add6dd16489f..ed32b9da484364d8f49e94f4c29342149ef563da 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.h +++ b/drivers/media/dvb/dvb-usb/gp8psk.h @@ -78,9 +78,6 @@ extern int dvb_usb_gp8psk_debug; #define ADV_MOD_DVB_BPSK 9 /* DVB-S BPSK */ #define GET_USB_SPEED 0x07 - #define USB_SPEED_LOW 0 - #define USB_SPEED_FULL 1 - #define USB_SPEED_HIGH 2 #define RESET_FX2 0x13 diff --git a/drivers/media/dvb/dvb-usb/technisat-usb2.c b/drivers/media/dvb/dvb-usb/technisat-usb2.c index 08f8842ad280861c7f6acb6c756939147f9d5879..473b95ed4d52759339b7b9f4b0c20541b76a569c 100644 --- a/drivers/media/dvb/dvb-usb/technisat-usb2.c +++ b/drivers/media/dvb/dvb-usb/technisat-usb2.c @@ -765,10 +765,8 @@ static void technisat_usb2_disconnect(struct usb_interface *intf) /* work and stuff was only created when the device is is hot-state */ if (dev != NULL) { struct technisat_usb2_state *state = dev->priv; - if (state != NULL) { + if (state != NULL) cancel_delayed_work_sync(&state->green_led_work); - flush_scheduled_work(); - } } dvb_usb_device_exit(intf); diff --git a/drivers/media/dvb/dvb-usb/vp7045.h b/drivers/media/dvb/dvb-usb/vp7045.h index 969688f8526750c8c9b8ea74d535ef1371885a49..cf5ec46f8bb1bbc40138af764be3f0a79f763aa1 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.h +++ b/drivers/media/dvb/dvb-usb/vp7045.h @@ -36,9 +36,6 @@ #define Tuner_Power_OFF 0 #define GET_USB_SPEED 0x07 - #define USB_SPEED_LOW 0 - #define USB_SPEED_FULL 1 - #define USB_SPEED_HIGH 2 #define LOCK_TUNER_COMMAND 0x09 diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c index 21c52e3b522e18df7ba3ff30412fc6f9650991af..489ae8245867bc51d83cfa062c71fc09952531b9 100644 --- a/drivers/media/dvb/firewire/firedtv-avc.c +++ b/drivers/media/dvb/firewire/firedtv-avc.c @@ -1208,7 +1208,7 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) if (r->response != AVC_RESPONSE_ACCEPTED) { dev_err(fdtv->device, "CA PMT failed with response 0x%x\n", r->response); - ret = -EFAULT; + ret = -EACCES; } out: mutex_unlock(&fdtv->avc_mutex); diff --git a/drivers/media/dvb/firewire/firedtv-ci.c b/drivers/media/dvb/firewire/firedtv-ci.c index 8ffb565f0704112cb10c63edc6cafb0aed6a3cd0..e5ebdbfe8c19e45c9f12b98639b44860d6a8b83e 100644 --- a/drivers/media/dvb/firewire/firedtv-ci.c +++ b/drivers/media/dvb/firewire/firedtv-ci.c @@ -45,11 +45,6 @@ static int fdtv_get_ca_flags(struct firedtv_tuner_status *stat) return flags; } -static int fdtv_ca_reset(struct firedtv *fdtv) -{ - return avc_ca_reset(fdtv) ? -EFAULT : 0; -} - static int fdtv_ca_get_caps(void *arg) { struct ca_caps *cap = arg; @@ -65,12 +60,14 @@ static int fdtv_ca_get_slot_info(struct firedtv *fdtv, void *arg) { struct firedtv_tuner_status stat; struct ca_slot_info *slot = arg; + int err; - if (avc_tuner_status(fdtv, &stat)) - return -EFAULT; + err = avc_tuner_status(fdtv, &stat); + if (err) + return err; if (slot->num != 0) - return -EFAULT; + return -EACCES; slot->type = CA_CI; slot->flags = fdtv_get_ca_flags(&stat); @@ -81,21 +78,21 @@ static int fdtv_ca_app_info(struct firedtv *fdtv, void *arg) { struct ca_msg *reply = arg; - return avc_ca_app_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; + return avc_ca_app_info(fdtv, reply->msg, &reply->length); } static int fdtv_ca_info(struct firedtv *fdtv, void *arg) { struct ca_msg *reply = arg; - return avc_ca_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; + return avc_ca_info(fdtv, reply->msg, &reply->length); } static int fdtv_ca_get_mmi(struct firedtv *fdtv, void *arg) { struct ca_msg *reply = arg; - return avc_ca_get_mmi(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; + return avc_ca_get_mmi(fdtv, reply->msg, &reply->length); } static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg) @@ -111,14 +108,15 @@ static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg) err = fdtv_ca_info(fdtv, arg); break; default: - if (avc_tuner_status(fdtv, &stat)) - err = -EFAULT; - else if (stat.ca_mmi == 1) + err = avc_tuner_status(fdtv, &stat); + if (err) + break; + if (stat.ca_mmi == 1) err = fdtv_ca_get_mmi(fdtv, arg); else { dev_info(fdtv->device, "unhandled CA message 0x%08x\n", fdtv->ca_last_command); - err = -EFAULT; + err = -EACCES; } } fdtv->ca_last_command = 0; @@ -141,7 +139,7 @@ static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg) data_length = msg->msg[3]; } - return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length) ? -EFAULT : 0; + return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length); } static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg) @@ -170,7 +168,7 @@ static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg) default: dev_err(fdtv->device, "unhandled CA message 0x%08x\n", fdtv->ca_last_command); - err = -EFAULT; + err = -EACCES; } return err; } @@ -184,7 +182,7 @@ static int fdtv_ca_ioctl(struct file *file, unsigned int cmd, void *arg) switch (cmd) { case CA_RESET: - err = fdtv_ca_reset(fdtv); + err = avc_ca_reset(fdtv); break; case CA_GET_CAP: err = fdtv_ca_get_caps(arg); diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 44b816f2601e7994c241fcdc3d0f782fbe29214c..32e08e35152525386b2b8c48ac9422b23913c59f 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -49,6 +49,27 @@ config DVB_STV6110x help A Silicon tuner that supports DVB-S and DVB-S2 modes +comment "Multistandard (cable + terrestrial) frontends" + depends on DVB_CORE + +config DVB_DRXK + tristate "Micronas DRXK based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + Micronas DRX-K DVB-C/T demodulator. + + Say Y when you want to support this frontend. + +config DVB_TDA18271C2DD + tristate "NXP TDA18271C2 silicon tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + NXP TDA18271 silicon tuner. + + Say Y when you want to support this tuner. + comment "DVB-S (satellite) frontends" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 2f3a6f736d641c1c59203a693a2c3f2b926e9ba4..6a6ba053ead4692eee52a9376e127f94c433ff7f 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -10,6 +10,7 @@ stv0900-objs = stv0900_core.o stv0900_sw.o au8522-objs = au8522_dig.o au8522_decoder.o drxd-objs = drxd_firm.o drxd_hard.o cxd2820r-objs = cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o +drxk-objs := drxk_hard.o obj-$(CONFIG_DVB_PLL) += dvb-pll.o obj-$(CONFIG_DVB_STV0299) += stv0299.o @@ -88,4 +89,6 @@ obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o obj-$(CONFIG_DVB_IX2505V) += ix2505v.o obj-$(CONFIG_DVB_STV0367) += stv0367.o obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o +obj-$(CONFIG_DVB_DRXK) += drxk.o +obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c index b537891a4cc9d8c2e647c68eec420a1e9aaa1723..2b248c12f404a96f839610040752e881a2a54fbf 100644 --- a/drivers/media/dvb/frontends/au8522_decoder.c +++ b/drivers/media/dvb/frontends/au8522_decoder.c @@ -692,7 +692,7 @@ static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) /* Interrogate the decoder to see if we are getting a real signal */ lock_status = au8522_readreg(state, 0x00); if (lock_status == 0xa2) - vt->signal = 0x01; + vt->signal = 0xffff; else vt->signal = 0x00; diff --git a/drivers/media/dvb/frontends/cx24113.c b/drivers/media/dvb/frontends/cx24113.c index e9ee55592fd31cbcf72c3c8edd3ca773112b1f21..c341d57d5e818d9c57d34e09e790eb937f0e5475 100644 --- a/drivers/media/dvb/frontends/cx24113.c +++ b/drivers/media/dvb/frontends/cx24113.c @@ -31,8 +31,8 @@ static int debug; -#define info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0) -#define err(args...) do { printk(KERN_ERR "CX24113: " args); } while (0) +#define cx_info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0) +#define cx_err(args...) do { printk(KERN_ERR "CX24113: " args); } while (0) #define dprintk(args...) \ do { \ @@ -341,7 +341,7 @@ static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f) } while (N < 6 && R < 3); if (N < 6) { - err("strange frequency: N < 6\n"); + cx_err("strange frequency: N < 6\n"); return; } F = freq_hz; @@ -563,7 +563,7 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe, kzalloc(sizeof(struct cx24113_state), GFP_KERNEL); int rc; if (state == NULL) { - err("Unable to kzalloc\n"); + cx_err("Unable to kzalloc\n"); goto error; } @@ -571,7 +571,7 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe, state->config = config; state->i2c = i2c; - info("trying to detect myself\n"); + cx_info("trying to detect myself\n"); /* making a dummy read, because of some expected troubles * after power on */ @@ -579,24 +579,24 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe, rc = cx24113_readreg(state, 0x00); if (rc < 0) { - info("CX24113 not found.\n"); + cx_info("CX24113 not found.\n"); goto error; } state->rev = rc; switch (rc) { case 0x43: - info("detected CX24113 variant\n"); + cx_info("detected CX24113 variant\n"); break; case REV_CX24113: - info("successfully detected\n"); + cx_info("successfully detected\n"); break; default: - err("unsupported device id: %x\n", state->rev); + cx_err("unsupported device id: %x\n", state->rev); goto error; } state->ver = cx24113_readreg(state, 0x01); - info("version: %x\n", state->ver); + cx_info("version: %x\n", state->ver); /* create dvb_frontend */ memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops, diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index 95c6465b87a12b71e39015f6bf896dd84c766db4..ccd05255d52730225530580b6bedec2a8df99336 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -1452,11 +1452,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe, cmd.args[0x00] = CMD_BANDWIDTH; cmd.args[0x01] = 0x00; cmd.len = 0x02; - ret = cx24116_cmd_execute(fe, &cmd); - if (ret != 0) - return ret; - - return ret; + return cx24116_cmd_execute(fe, &cmd); } static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, diff --git a/drivers/media/dvb/frontends/cxd2820r.h b/drivers/media/dvb/frontends/cxd2820r.h index ad17845123d9e41881a99b65dd908f043aee40bb..2906582dc94c20a5ed58460b4d4b3a59e0332e84 100644 --- a/drivers/media/dvb/frontends/cxd2820r.h +++ b/drivers/media/dvb/frontends/cxd2820r.h @@ -55,13 +55,13 @@ struct cxd2820r_config { * Default: 0 * Values: 0, 1 */ - int if_agc_polarity:1; + bool if_agc_polarity; /* Spectrum inversion. * Default: 0 * Values: 0, 1 */ - int spec_inv:1; + bool spec_inv; /* IFs for all used modes. * Default: none, must set diff --git a/drivers/media/dvb/frontends/cxd2820r_core.c b/drivers/media/dvb/frontends/cxd2820r_core.c index 0779f69db793501302aa1df7c02ef0311b78fa30..d416e85589e1150fe57c7b204a86b6c62ef8b6d2 100644 --- a/drivers/media/dvb/frontends/cxd2820r_core.c +++ b/drivers/media/dvb/frontends/cxd2820r_core.c @@ -314,6 +314,8 @@ static int cxd2820r_set_frontend(struct dvb_frontend *fe, } else if (c->delivery_system == SYS_DVBT2) { /* DVB-T => DVB-T2 */ ret = cxd2820r_sleep_t(fe); + if (ret) + break; ret = cxd2820r_set_frontend_t2(fe, p); } break; @@ -324,6 +326,8 @@ static int cxd2820r_set_frontend(struct dvb_frontend *fe, } else if (c->delivery_system == SYS_DVBT) { /* DVB-T2 => DVB-T */ ret = cxd2820r_sleep_t2(fe); + if (ret) + break; ret = cxd2820r_set_frontend_t(fe, p); } break; @@ -740,12 +744,13 @@ static int cxd2820r_tuner_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) { struct cxd2820r_priv *priv = i2c_get_adapdata(i2c_adap); - u8 obuf[msg[0].len + 2]; + int ret; + u8 *obuf = kmalloc(msg[0].len + 2, GFP_KERNEL); struct i2c_msg msg2[2] = { { .addr = priv->cfg.i2c_address, .flags = 0, - .len = sizeof(obuf), + .len = msg[0].len + 2, .buf = obuf, }, { .addr = priv->cfg.i2c_address, @@ -755,15 +760,24 @@ static int cxd2820r_tuner_i2c_xfer(struct i2c_adapter *i2c_adap, } }; + if (!obuf) + return -ENOMEM; + obuf[0] = 0x09; obuf[1] = (msg[0].addr << 1); if (num == 2) { /* I2C read */ obuf[1] = (msg[0].addr << 1) | I2C_M_RD; /* I2C RD flag */ - msg2[0].len = sizeof(obuf) - 1; /* maybe HW bug ? */ + msg2[0].len = msg[0].len + 2 - 1; /* '-1' maybe HW bug ? */ } memcpy(&obuf[2], msg[0].buf, msg[0].len); - return i2c_transfer(priv->i2c, msg2, num); + ret = i2c_transfer(priv->i2c, msg2, num); + if (ret < 0) + warn("tuner i2c failed ret:%d", ret); + + kfree(obuf); + + return ret; } static struct i2c_algorithm cxd2820r_tuner_i2c_algo = { diff --git a/drivers/media/dvb/frontends/cxd2820r_priv.h b/drivers/media/dvb/frontends/cxd2820r_priv.h index 25adbeefa6d3b1df632d89246cd99bd92a83d88f..0c0ebc9d5c4ac0ca7a051fa0c64b55dc23d6aa70 100644 --- a/drivers/media/dvb/frontends/cxd2820r_priv.h +++ b/drivers/media/dvb/frontends/cxd2820r_priv.h @@ -55,13 +55,13 @@ struct cxd2820r_priv { struct mutex fe_lock; /* FE lock */ int active_fe:2; /* FE lock, -1=NONE, 0=DVB-T/T2, 1=DVB-C */ - int ber_running:1; + bool ber_running; u8 bank[2]; u8 gpio[3]; fe_delivery_system_t delivery_system; - int last_tune_failed:1; /* for switch between T and T2 tune */ + bool last_tune_failed; /* for switch between T and T2 tune */ }; /* cxd2820r_core.c */ diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 0c9f40c2a251fbaad72fe3520e6f6ec48d76cb13..a64a538ba36439b5723650905f434d8fba8ae58b 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -2336,6 +2336,11 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, request_firmware() will hit an OOPS (this should be moved somewhere more common) */ + /* FIXME: make sure the dev.parent field is initialized, or else + request_firmware() will hit an OOPS (this should be moved somewhere + more common) */ + st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent; + dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr); /* init 7090 tuner adapter */ diff --git a/drivers/media/dvb/frontends/drxd_hard.c b/drivers/media/dvb/frontends/drxd_hard.c index ea4c1c361d2b7a12473cd1d9ff6ec19a0aa977a8..2238bf0be95936320feccbfc65f30c1503167e08 100644 --- a/drivers/media/dvb/frontends/drxd_hard.c +++ b/drivers/media/dvb/frontends/drxd_hard.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include "dvb_frontend.h" @@ -233,7 +232,7 @@ static int i2c_read(struct i2c_adapter *adap, return 0; } -inline u32 MulDiv32(u32 a, u32 b, u32 c) +static inline u32 MulDiv32(u32 a, u32 b, u32 c) { u64 tmp64; @@ -910,14 +909,16 @@ static int load_firmware(struct drxd_state *state, const char *fw_name) return -EIO; } - state->microcode = kzalloc(fw->size, GFP_KERNEL); + state->microcode = kmalloc(fw->size, GFP_KERNEL); if (state->microcode == NULL) { - printk(KERN_ERR "drxd: firmware load failure: nomemory\n"); + release_firmware(fw); + printk(KERN_ERR "drxd: firmware load failure: no memory\n"); return -ENOMEM; } memcpy(state->microcode, fw->data, fw->size); state->microcode_length = fw->size; + release_firmware(fw); return 0; } diff --git a/drivers/media/dvb/frontends/drxk.h b/drivers/media/dvb/frontends/drxk.h new file mode 100644 index 0000000000000000000000000000000000000000..58baf419560cedb55f11ca5b788cbcd9eff77069 --- /dev/null +++ b/drivers/media/dvb/frontends/drxk.h @@ -0,0 +1,47 @@ +#ifndef _DRXK_H_ +#define _DRXK_H_ + +#include +#include + +/** + * struct drxk_config - Configure the initial parameters for DRX-K + * + * adr: I2C Address of the DRX-K + * single_master: Device is on the single master mode + * no_i2c_bridge: Don't switch the I2C bridge to talk with tuner + * antenna_gpio: GPIO bit used to control the antenna + * antenna_dvbt: GPIO bit for changing antenna to DVB-C. A value of 1 + * means that 1=DVBC, 0 = DVBT. Zero means the opposite. + * microcode_name: Name of the firmware file with the microcode + * + * On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is + * UIO-3. + */ +struct drxk_config { + u8 adr; + bool single_master; + bool no_i2c_bridge; + + bool antenna_dvbt; + u16 antenna_gpio; + + const char *microcode_name; +}; + +#if defined(CONFIG_DVB_DRXK) || (defined(CONFIG_DVB_DRXK_MODULE) \ + && defined(MODULE)) +extern struct dvb_frontend *drxk_attach(const struct drxk_config *config, + struct i2c_adapter *i2c, + struct dvb_frontend **fe_t); +#else +static inline struct dvb_frontend *drxk_attach(const struct drxk_config *config, + struct i2c_adapter *i2c, + struct dvb_frontend **fe_t) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb/frontends/drxk_hard.c new file mode 100644 index 0000000000000000000000000000000000000000..41b083820dae96ff726b1cca505ba7a8415bb85c --- /dev/null +++ b/drivers/media/dvb/frontends/drxk_hard.c @@ -0,0 +1,6454 @@ +/* + * drxk_hard: DRX-K DVB-C/T demodulator driver + * + * Copyright (C) 2010-2011 Digital Devices GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "drxk.h" +#include "drxk_hard.h" + +static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode); +static int PowerDownQAM(struct drxk_state *state); +static int SetDVBTStandard(struct drxk_state *state, + enum OperationMode oMode); +static int SetQAMStandard(struct drxk_state *state, + enum OperationMode oMode); +static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, + s32 tunerFreqOffset); +static int SetDVBTStandard(struct drxk_state *state, + enum OperationMode oMode); +static int DVBTStart(struct drxk_state *state); +static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, + s32 tunerFreqOffset); +static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus); +static int GetDVBTLockStatus(struct drxk_state *state, u32 *pLockStatus); +static int SwitchAntennaToQAM(struct drxk_state *state); +static int SwitchAntennaToDVBT(struct drxk_state *state); + +static bool IsDVBT(struct drxk_state *state) +{ + return state->m_OperationMode == OM_DVBT; +} + +static bool IsQAM(struct drxk_state *state) +{ + return state->m_OperationMode == OM_QAM_ITU_A || + state->m_OperationMode == OM_QAM_ITU_B || + state->m_OperationMode == OM_QAM_ITU_C; +} + +bool IsA1WithPatchCode(struct drxk_state *state) +{ + return state->m_DRXK_A1_PATCH_CODE; +} + +bool IsA1WithRomCode(struct drxk_state *state) +{ + return state->m_DRXK_A1_ROM_CODE; +} + +#define NOA1ROM 0 + +#define DRXDAP_FASI_SHORT_FORMAT(addr) (((addr) & 0xFC30FF80) == 0) +#define DRXDAP_FASI_LONG_FORMAT(addr) (((addr) & 0xFC30FF80) != 0) + +#define DEFAULT_MER_83 165 +#define DEFAULT_MER_93 250 + +#ifndef DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH +#define DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH (0x02) +#endif + +#ifndef DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH +#define DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH (0x03) +#endif + +#ifndef DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH +#define DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH (0x06) +#endif + +#define DEFAULT_DRXK_MPEG_LOCK_TIMEOUT 700 +#define DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT 500 + +#ifndef DRXK_KI_RAGC_ATV +#define DRXK_KI_RAGC_ATV 4 +#endif +#ifndef DRXK_KI_IAGC_ATV +#define DRXK_KI_IAGC_ATV 6 +#endif +#ifndef DRXK_KI_DAGC_ATV +#define DRXK_KI_DAGC_ATV 7 +#endif + +#ifndef DRXK_KI_RAGC_QAM +#define DRXK_KI_RAGC_QAM 3 +#endif +#ifndef DRXK_KI_IAGC_QAM +#define DRXK_KI_IAGC_QAM 4 +#endif +#ifndef DRXK_KI_DAGC_QAM +#define DRXK_KI_DAGC_QAM 7 +#endif +#ifndef DRXK_KI_RAGC_DVBT +#define DRXK_KI_RAGC_DVBT (IsA1WithPatchCode(state) ? 3 : 2) +#endif +#ifndef DRXK_KI_IAGC_DVBT +#define DRXK_KI_IAGC_DVBT (IsA1WithPatchCode(state) ? 4 : 2) +#endif +#ifndef DRXK_KI_DAGC_DVBT +#define DRXK_KI_DAGC_DVBT (IsA1WithPatchCode(state) ? 10 : 7) +#endif + +#ifndef DRXK_AGC_DAC_OFFSET +#define DRXK_AGC_DAC_OFFSET (0x800) +#endif + +#ifndef DRXK_BANDWIDTH_8MHZ_IN_HZ +#define DRXK_BANDWIDTH_8MHZ_IN_HZ (0x8B8249L) +#endif + +#ifndef DRXK_BANDWIDTH_7MHZ_IN_HZ +#define DRXK_BANDWIDTH_7MHZ_IN_HZ (0x7A1200L) +#endif + +#ifndef DRXK_BANDWIDTH_6MHZ_IN_HZ +#define DRXK_BANDWIDTH_6MHZ_IN_HZ (0x68A1B6L) +#endif + +#ifndef DRXK_QAM_SYMBOLRATE_MAX +#define DRXK_QAM_SYMBOLRATE_MAX (7233000) +#endif + +#define DRXK_BL_ROM_OFFSET_TAPS_DVBT 56 +#define DRXK_BL_ROM_OFFSET_TAPS_ITU_A 64 +#define DRXK_BL_ROM_OFFSET_TAPS_ITU_C 0x5FE0 +#define DRXK_BL_ROM_OFFSET_TAPS_BG 24 +#define DRXK_BL_ROM_OFFSET_TAPS_DKILLP 32 +#define DRXK_BL_ROM_OFFSET_TAPS_NTSC 40 +#define DRXK_BL_ROM_OFFSET_TAPS_FM 48 +#define DRXK_BL_ROM_OFFSET_UCODE 0 + +#define DRXK_BLC_TIMEOUT 100 + +#define DRXK_BLCC_NR_ELEMENTS_TAPS 2 +#define DRXK_BLCC_NR_ELEMENTS_UCODE 6 + +#define DRXK_BLDC_NR_ELEMENTS_TAPS 28 + +#ifndef DRXK_OFDM_NE_NOTCH_WIDTH +#define DRXK_OFDM_NE_NOTCH_WIDTH (4) +#endif + +#define DRXK_QAM_SL_SIG_POWER_QAM16 (40960) +#define DRXK_QAM_SL_SIG_POWER_QAM32 (20480) +#define DRXK_QAM_SL_SIG_POWER_QAM64 (43008) +#define DRXK_QAM_SL_SIG_POWER_QAM128 (20992) +#define DRXK_QAM_SL_SIG_POWER_QAM256 (43520) + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debug messages"); + +#define dprintk(level, fmt, arg...) do { \ +if (debug >= level) \ + printk(KERN_DEBUG "drxk: %s" fmt, __func__, ## arg); \ +} while (0) + + +static inline u32 MulDiv32(u32 a, u32 b, u32 c) +{ + u64 tmp64; + + tmp64 = (u64) a * (u64) b; + do_div(tmp64, c); + + return (u32) tmp64; +} + +inline u32 Frac28a(u32 a, u32 c) +{ + int i = 0; + u32 Q1 = 0; + u32 R0 = 0; + + R0 = (a % c) << 4; /* 32-28 == 4 shifts possible at max */ + Q1 = a / c; /* integer part, only the 4 least significant bits + will be visible in the result */ + + /* division using radix 16, 7 nibbles in the result */ + for (i = 0; i < 7; i++) { + Q1 = (Q1 << 4) | (R0 / c); + R0 = (R0 % c) << 4; + } + /* rounding */ + if ((R0 >> 3) >= c) + Q1++; + + return Q1; +} + +static u32 Log10Times100(u32 x) +{ + static const u8 scale = 15; + static const u8 indexWidth = 5; + u8 i = 0; + u32 y = 0; + u32 d = 0; + u32 k = 0; + u32 r = 0; + /* + log2lut[n] = (1< 0; k--) { + if (x & (((u32) 1) << scale)) + break; + x <<= 1; + } + } else { + for (k = scale; k < 31; k++) { + if ((x & (((u32) (-1)) << (scale + 1))) == 0) + break; + x >>= 1; + } + } + /* + Now x has binary point between bit[scale] and bit[scale-1] + and 1.0 <= x < 2.0 */ + + /* correction for divison: log(x) = log(x/y)+log(y) */ + y = k * ((((u32) 1) << scale) * 200); + + /* remove integer part */ + x &= ((((u32) 1) << scale) - 1); + /* get index */ + i = (u8) (x >> (scale - indexWidth)); + /* compute delta (x - a) */ + d = x & ((((u32) 1) << (scale - indexWidth)) - 1); + /* compute log, multiplication (d* (..)) must be within range ! */ + y += log2lut[i] + + ((d * (log2lut[i + 1] - log2lut[i])) >> (scale - indexWidth)); + /* Conver to log10() */ + y /= 108853; /* (log2(10) << scale) */ + r = (y >> 1); + /* rounding */ + if (y & ((u32) 1)) + r++; + return r; +} + +/****************************************************************************/ +/* I2C **********************************************************************/ +/****************************************************************************/ + +static int i2c_read1(struct i2c_adapter *adapter, u8 adr, u8 *val) +{ + struct i2c_msg msgs[1] = { {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1} + }; + + return i2c_transfer(adapter, msgs, 1); +} + +static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) +{ + int status; + struct i2c_msg msg = { + .addr = adr, .flags = 0, .buf = data, .len = len }; + + dprintk(3, ":"); + if (debug > 2) { + int i; + for (i = 0; i < len; i++) + printk(KERN_CONT " %02x", data[i]); + printk(KERN_CONT "\n"); + } + status = i2c_transfer(adap, &msg, 1); + if (status >= 0 && status != 1) + status = -EIO; + + if (status < 0) + printk(KERN_ERR "drxk: i2c write error at addr 0x%02x\n", adr); + + return status; +} + +static int i2c_read(struct i2c_adapter *adap, + u8 adr, u8 *msg, int len, u8 *answ, int alen) +{ + int status; + struct i2c_msg msgs[2] = { + {.addr = adr, .flags = 0, + .buf = msg, .len = len}, + {.addr = adr, .flags = I2C_M_RD, + .buf = answ, .len = alen} + }; + + status = i2c_transfer(adap, msgs, 2); + if (status != 2) { + if (debug > 2) + printk(KERN_CONT ": ERROR!\n"); + if (status >= 0) + status = -EIO; + + printk(KERN_ERR "drxk: i2c read error at addr 0x%02x\n", adr); + return status; + } + if (debug > 2) { + int i; + dprintk(2, ": read from "); + for (i = 0; i < len; i++) + printk(KERN_CONT " %02x", msg[i]); + printk(KERN_CONT "Value = "); + for (i = 0; i < alen; i++) + printk(KERN_CONT " %02x", answ[i]); + printk(KERN_CONT "\n"); + } + return 0; +} + +static int read16_flags(struct drxk_state *state, u32 reg, u16 *data, u8 flags) +{ + int status; + u8 adr = state->demod_address, mm1[4], mm2[2], len; + + if (state->single_master) + flags |= 0xC0; + + if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) { + mm1[0] = (((reg << 1) & 0xFF) | 0x01); + mm1[1] = ((reg >> 16) & 0xFF); + mm1[2] = ((reg >> 24) & 0xFF) | flags; + mm1[3] = ((reg >> 7) & 0xFF); + len = 4; + } else { + mm1[0] = ((reg << 1) & 0xFF); + mm1[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0)); + len = 2; + } + dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags); + status = i2c_read(state->i2c, adr, mm1, len, mm2, 2); + if (status < 0) + return status; + if (data) + *data = mm2[0] | (mm2[1] << 8); + + return 0; +} + +static int read16(struct drxk_state *state, u32 reg, u16 *data) +{ + return read16_flags(state, reg, data, 0); +} + +static int read32_flags(struct drxk_state *state, u32 reg, u32 *data, u8 flags) +{ + int status; + u8 adr = state->demod_address, mm1[4], mm2[4], len; + + if (state->single_master) + flags |= 0xC0; + + if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) { + mm1[0] = (((reg << 1) & 0xFF) | 0x01); + mm1[1] = ((reg >> 16) & 0xFF); + mm1[2] = ((reg >> 24) & 0xFF) | flags; + mm1[3] = ((reg >> 7) & 0xFF); + len = 4; + } else { + mm1[0] = ((reg << 1) & 0xFF); + mm1[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0)); + len = 2; + } + dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags); + status = i2c_read(state->i2c, adr, mm1, len, mm2, 4); + if (status < 0) + return status; + if (data) + *data = mm2[0] | (mm2[1] << 8) | + (mm2[2] << 16) | (mm2[3] << 24); + + return 0; +} + +static int read32(struct drxk_state *state, u32 reg, u32 *data) +{ + return read32_flags(state, reg, data, 0); +} + +static int write16_flags(struct drxk_state *state, u32 reg, u16 data, u8 flags) +{ + u8 adr = state->demod_address, mm[6], len; + + if (state->single_master) + flags |= 0xC0; + if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) { + mm[0] = (((reg << 1) & 0xFF) | 0x01); + mm[1] = ((reg >> 16) & 0xFF); + mm[2] = ((reg >> 24) & 0xFF) | flags; + mm[3] = ((reg >> 7) & 0xFF); + len = 4; + } else { + mm[0] = ((reg << 1) & 0xFF); + mm[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0)); + len = 2; + } + mm[len] = data & 0xff; + mm[len + 1] = (data >> 8) & 0xff; + + dprintk(2, "(0x%08x, 0x%04x, 0x%02x)\n", reg, data, flags); + return i2c_write(state->i2c, adr, mm, len + 2); +} + +static int write16(struct drxk_state *state, u32 reg, u16 data) +{ + return write16_flags(state, reg, data, 0); +} + +static int write32_flags(struct drxk_state *state, u32 reg, u32 data, u8 flags) +{ + u8 adr = state->demod_address, mm[8], len; + + if (state->single_master) + flags |= 0xC0; + if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) { + mm[0] = (((reg << 1) & 0xFF) | 0x01); + mm[1] = ((reg >> 16) & 0xFF); + mm[2] = ((reg >> 24) & 0xFF) | flags; + mm[3] = ((reg >> 7) & 0xFF); + len = 4; + } else { + mm[0] = ((reg << 1) & 0xFF); + mm[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0)); + len = 2; + } + mm[len] = data & 0xff; + mm[len + 1] = (data >> 8) & 0xff; + mm[len + 2] = (data >> 16) & 0xff; + mm[len + 3] = (data >> 24) & 0xff; + dprintk(2, "(0x%08x, 0x%08x, 0x%02x)\n", reg, data, flags); + + return i2c_write(state->i2c, adr, mm, len + 4); +} + +static int write32(struct drxk_state *state, u32 reg, u32 data) +{ + return write32_flags(state, reg, data, 0); +} + +static int write_block(struct drxk_state *state, u32 Address, + const int BlockSize, const u8 pBlock[]) +{ + int status = 0, BlkSize = BlockSize; + u8 Flags = 0; + + if (state->single_master) + Flags |= 0xC0; + + while (BlkSize > 0) { + int Chunk = BlkSize > state->m_ChunkSize ? + state->m_ChunkSize : BlkSize; + u8 *AdrBuf = &state->Chunk[0]; + u32 AdrLength = 0; + + if (DRXDAP_FASI_LONG_FORMAT(Address) || (Flags != 0)) { + AdrBuf[0] = (((Address << 1) & 0xFF) | 0x01); + AdrBuf[1] = ((Address >> 16) & 0xFF); + AdrBuf[2] = ((Address >> 24) & 0xFF); + AdrBuf[3] = ((Address >> 7) & 0xFF); + AdrBuf[2] |= Flags; + AdrLength = 4; + if (Chunk == state->m_ChunkSize) + Chunk -= 2; + } else { + AdrBuf[0] = ((Address << 1) & 0xFF); + AdrBuf[1] = (((Address >> 16) & 0x0F) | + ((Address >> 18) & 0xF0)); + AdrLength = 2; + } + memcpy(&state->Chunk[AdrLength], pBlock, Chunk); + dprintk(2, "(0x%08x, 0x%02x)\n", Address, Flags); + if (debug > 1) { + int i; + if (pBlock) + for (i = 0; i < Chunk; i++) + printk(KERN_CONT " %02x", pBlock[i]); + printk(KERN_CONT "\n"); + } + status = i2c_write(state->i2c, state->demod_address, + &state->Chunk[0], Chunk + AdrLength); + if (status < 0) { + printk(KERN_ERR "drxk: %s: i2c write error at addr 0x%02x\n", + __func__, Address); + break; + } + pBlock += Chunk; + Address += (Chunk >> 1); + BlkSize -= Chunk; + } + return status; +} + +#ifndef DRXK_MAX_RETRIES_POWERUP +#define DRXK_MAX_RETRIES_POWERUP 20 +#endif + +int PowerUpDevice(struct drxk_state *state) +{ + int status; + u8 data = 0; + u16 retryCount = 0; + + dprintk(1, "\n"); + + status = i2c_read1(state->i2c, state->demod_address, &data); + if (status < 0) { + do { + data = 0; + status = i2c_write(state->i2c, state->demod_address, + &data, 1); + msleep(10); + retryCount++; + if (status < 0) + continue; + status = i2c_read1(state->i2c, state->demod_address, + &data); + } while (status < 0 && + (retryCount < DRXK_MAX_RETRIES_POWERUP)); + if (status < 0 && retryCount >= DRXK_MAX_RETRIES_POWERUP) + goto error; + } + + /* Make sure all clk domains are active */ + status = write16(state, SIO_CC_PWD_MODE__A, SIO_CC_PWD_MODE_LEVEL_NONE); + if (status < 0) + goto error; + status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY); + if (status < 0) + goto error; + /* Enable pll lock tests */ + status = write16(state, SIO_CC_PLL_LOCK__A, 1); + if (status < 0) + goto error; + + state->m_currentPowerMode = DRX_POWER_UP; + +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + + return status; +} + + +static int init_state(struct drxk_state *state) +{ + /* + * FIXME: most (all?) of the values bellow should be moved into + * struct drxk_config, as they are probably board-specific + */ + u32 ulVSBIfAgcMode = DRXK_AGC_CTRL_AUTO; + u32 ulVSBIfAgcOutputLevel = 0; + u32 ulVSBIfAgcMinLevel = 0; + u32 ulVSBIfAgcMaxLevel = 0x7FFF; + u32 ulVSBIfAgcSpeed = 3; + + u32 ulVSBRfAgcMode = DRXK_AGC_CTRL_AUTO; + u32 ulVSBRfAgcOutputLevel = 0; + u32 ulVSBRfAgcMinLevel = 0; + u32 ulVSBRfAgcMaxLevel = 0x7FFF; + u32 ulVSBRfAgcSpeed = 3; + u32 ulVSBRfAgcTop = 9500; + u32 ulVSBRfAgcCutOffCurrent = 4000; + + u32 ulATVIfAgcMode = DRXK_AGC_CTRL_AUTO; + u32 ulATVIfAgcOutputLevel = 0; + u32 ulATVIfAgcMinLevel = 0; + u32 ulATVIfAgcMaxLevel = 0; + u32 ulATVIfAgcSpeed = 3; + + u32 ulATVRfAgcMode = DRXK_AGC_CTRL_OFF; + u32 ulATVRfAgcOutputLevel = 0; + u32 ulATVRfAgcMinLevel = 0; + u32 ulATVRfAgcMaxLevel = 0; + u32 ulATVRfAgcTop = 9500; + u32 ulATVRfAgcCutOffCurrent = 4000; + u32 ulATVRfAgcSpeed = 3; + + u32 ulQual83 = DEFAULT_MER_83; + u32 ulQual93 = DEFAULT_MER_93; + + u32 ulDVBTStaticTSClock = 1; + u32 ulDVBCStaticTSClock = 1; + + u32 ulMpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT; + u32 ulDemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT; + + /* io_pad_cfg register (8 bit reg.) MSB bit is 1 (default value) */ + /* io_pad_cfg_mode output mode is drive always */ + /* io_pad_cfg_drive is set to power 2 (23 mA) */ + u32 ulGPIOCfg = 0x0113; + u32 ulSerialMode = 1; + u32 ulInvertTSClock = 0; + u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH; + u32 ulTSClockkStrength = DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH; + u32 ulDVBTBitrate = 50000000; + u32 ulDVBCBitrate = DRXK_QAM_SYMBOLRATE_MAX * 8; + + u32 ulInsertRSByte = 0; + + u32 ulRfMirror = 1; + u32 ulPowerDown = 0; + + dprintk(1, "\n"); + + state->m_hasLNA = false; + state->m_hasDVBT = false; + state->m_hasDVBC = false; + state->m_hasATV = false; + state->m_hasOOB = false; + state->m_hasAudio = false; + + state->m_ChunkSize = 124; + + state->m_oscClockFreq = 0; + state->m_smartAntInverted = false; + state->m_bPDownOpenBridge = false; + + /* real system clock frequency in kHz */ + state->m_sysClockFreq = 151875; + /* Timing div, 250ns/Psys */ + /* Timing div, = (delay (nano seconds) * sysclk (kHz))/ 1000 */ + state->m_HICfgTimingDiv = ((state->m_sysClockFreq / 1000) * + HI_I2C_DELAY) / 1000; + /* Clipping */ + if (state->m_HICfgTimingDiv > SIO_HI_RA_RAM_PAR_2_CFG_DIV__M) + state->m_HICfgTimingDiv = SIO_HI_RA_RAM_PAR_2_CFG_DIV__M; + state->m_HICfgWakeUpKey = (state->demod_address << 1); + /* port/bridge/power down ctrl */ + state->m_HICfgCtrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE; + + state->m_bPowerDown = (ulPowerDown != 0); + + state->m_DRXK_A1_PATCH_CODE = false; + state->m_DRXK_A1_ROM_CODE = false; + state->m_DRXK_A2_ROM_CODE = false; + state->m_DRXK_A3_ROM_CODE = false; + state->m_DRXK_A2_PATCH_CODE = false; + state->m_DRXK_A3_PATCH_CODE = false; + + /* Init AGC and PGA parameters */ + /* VSB IF */ + state->m_vsbIfAgcCfg.ctrlMode = (ulVSBIfAgcMode); + state->m_vsbIfAgcCfg.outputLevel = (ulVSBIfAgcOutputLevel); + state->m_vsbIfAgcCfg.minOutputLevel = (ulVSBIfAgcMinLevel); + state->m_vsbIfAgcCfg.maxOutputLevel = (ulVSBIfAgcMaxLevel); + state->m_vsbIfAgcCfg.speed = (ulVSBIfAgcSpeed); + state->m_vsbPgaCfg = 140; + + /* VSB RF */ + state->m_vsbRfAgcCfg.ctrlMode = (ulVSBRfAgcMode); + state->m_vsbRfAgcCfg.outputLevel = (ulVSBRfAgcOutputLevel); + state->m_vsbRfAgcCfg.minOutputLevel = (ulVSBRfAgcMinLevel); + state->m_vsbRfAgcCfg.maxOutputLevel = (ulVSBRfAgcMaxLevel); + state->m_vsbRfAgcCfg.speed = (ulVSBRfAgcSpeed); + state->m_vsbRfAgcCfg.top = (ulVSBRfAgcTop); + state->m_vsbRfAgcCfg.cutOffCurrent = (ulVSBRfAgcCutOffCurrent); + state->m_vsbPreSawCfg.reference = 0x07; + state->m_vsbPreSawCfg.usePreSaw = true; + + state->m_Quality83percent = DEFAULT_MER_83; + state->m_Quality93percent = DEFAULT_MER_93; + if (ulQual93 <= 500 && ulQual83 < ulQual93) { + state->m_Quality83percent = ulQual83; + state->m_Quality93percent = ulQual93; + } + + /* ATV IF */ + state->m_atvIfAgcCfg.ctrlMode = (ulATVIfAgcMode); + state->m_atvIfAgcCfg.outputLevel = (ulATVIfAgcOutputLevel); + state->m_atvIfAgcCfg.minOutputLevel = (ulATVIfAgcMinLevel); + state->m_atvIfAgcCfg.maxOutputLevel = (ulATVIfAgcMaxLevel); + state->m_atvIfAgcCfg.speed = (ulATVIfAgcSpeed); + + /* ATV RF */ + state->m_atvRfAgcCfg.ctrlMode = (ulATVRfAgcMode); + state->m_atvRfAgcCfg.outputLevel = (ulATVRfAgcOutputLevel); + state->m_atvRfAgcCfg.minOutputLevel = (ulATVRfAgcMinLevel); + state->m_atvRfAgcCfg.maxOutputLevel = (ulATVRfAgcMaxLevel); + state->m_atvRfAgcCfg.speed = (ulATVRfAgcSpeed); + state->m_atvRfAgcCfg.top = (ulATVRfAgcTop); + state->m_atvRfAgcCfg.cutOffCurrent = (ulATVRfAgcCutOffCurrent); + state->m_atvPreSawCfg.reference = 0x04; + state->m_atvPreSawCfg.usePreSaw = true; + + + /* DVBT RF */ + state->m_dvbtRfAgcCfg.ctrlMode = DRXK_AGC_CTRL_OFF; + state->m_dvbtRfAgcCfg.outputLevel = 0; + state->m_dvbtRfAgcCfg.minOutputLevel = 0; + state->m_dvbtRfAgcCfg.maxOutputLevel = 0xFFFF; + state->m_dvbtRfAgcCfg.top = 0x2100; + state->m_dvbtRfAgcCfg.cutOffCurrent = 4000; + state->m_dvbtRfAgcCfg.speed = 1; + + + /* DVBT IF */ + state->m_dvbtIfAgcCfg.ctrlMode = DRXK_AGC_CTRL_AUTO; + state->m_dvbtIfAgcCfg.outputLevel = 0; + state->m_dvbtIfAgcCfg.minOutputLevel = 0; + state->m_dvbtIfAgcCfg.maxOutputLevel = 9000; + state->m_dvbtIfAgcCfg.top = 13424; + state->m_dvbtIfAgcCfg.cutOffCurrent = 0; + state->m_dvbtIfAgcCfg.speed = 3; + state->m_dvbtIfAgcCfg.FastClipCtrlDelay = 30; + state->m_dvbtIfAgcCfg.IngainTgtMax = 30000; + /* state->m_dvbtPgaCfg = 140; */ + + state->m_dvbtPreSawCfg.reference = 4; + state->m_dvbtPreSawCfg.usePreSaw = false; + + /* QAM RF */ + state->m_qamRfAgcCfg.ctrlMode = DRXK_AGC_CTRL_OFF; + state->m_qamRfAgcCfg.outputLevel = 0; + state->m_qamRfAgcCfg.minOutputLevel = 6023; + state->m_qamRfAgcCfg.maxOutputLevel = 27000; + state->m_qamRfAgcCfg.top = 0x2380; + state->m_qamRfAgcCfg.cutOffCurrent = 4000; + state->m_qamRfAgcCfg.speed = 3; + + /* QAM IF */ + state->m_qamIfAgcCfg.ctrlMode = DRXK_AGC_CTRL_AUTO; + state->m_qamIfAgcCfg.outputLevel = 0; + state->m_qamIfAgcCfg.minOutputLevel = 0; + state->m_qamIfAgcCfg.maxOutputLevel = 9000; + state->m_qamIfAgcCfg.top = 0x0511; + state->m_qamIfAgcCfg.cutOffCurrent = 0; + state->m_qamIfAgcCfg.speed = 3; + state->m_qamIfAgcCfg.IngainTgtMax = 5119; + state->m_qamIfAgcCfg.FastClipCtrlDelay = 50; + + state->m_qamPgaCfg = 140; + state->m_qamPreSawCfg.reference = 4; + state->m_qamPreSawCfg.usePreSaw = false; + + state->m_OperationMode = OM_NONE; + state->m_DrxkState = DRXK_UNINITIALIZED; + + /* MPEG output configuration */ + state->m_enableMPEGOutput = true; /* If TRUE; enable MPEG ouput */ + state->m_insertRSByte = false; /* If TRUE; insert RS byte */ + state->m_enableParallel = true; /* If TRUE; + parallel out otherwise serial */ + state->m_invertDATA = false; /* If TRUE; invert DATA signals */ + state->m_invertERR = false; /* If TRUE; invert ERR signal */ + state->m_invertSTR = false; /* If TRUE; invert STR signals */ + state->m_invertVAL = false; /* If TRUE; invert VAL signals */ + state->m_invertCLK = (ulInvertTSClock != 0); /* If TRUE; invert CLK signals */ + state->m_DVBTStaticCLK = (ulDVBTStaticTSClock != 0); + state->m_DVBCStaticCLK = (ulDVBCStaticTSClock != 0); + /* If TRUE; static MPEG clockrate will be used; + otherwise clockrate will adapt to the bitrate of the TS */ + + state->m_DVBTBitrate = ulDVBTBitrate; + state->m_DVBCBitrate = ulDVBCBitrate; + + state->m_TSDataStrength = (ulTSDataStrength & 0x07); + state->m_TSClockkStrength = (ulTSClockkStrength & 0x07); + + /* Maximum bitrate in b/s in case static clockrate is selected */ + state->m_mpegTsStaticBitrate = 19392658; + state->m_disableTEIhandling = false; + + if (ulInsertRSByte) + state->m_insertRSByte = true; + + state->m_MpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT; + if (ulMpegLockTimeOut < 10000) + state->m_MpegLockTimeOut = ulMpegLockTimeOut; + state->m_DemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT; + if (ulDemodLockTimeOut < 10000) + state->m_DemodLockTimeOut = ulDemodLockTimeOut; + + /* QAM defaults */ + state->m_Constellation = DRX_CONSTELLATION_AUTO; + state->m_qamInterleaveMode = DRXK_QAM_I12_J17; + state->m_fecRsPlen = 204 * 8; /* fecRsPlen annex A */ + state->m_fecRsPrescale = 1; + + state->m_sqiSpeed = DRXK_DVBT_SQI_SPEED_MEDIUM; + state->m_agcFastClipCtrlDelay = 0; + + state->m_GPIOCfg = (ulGPIOCfg); + + state->m_bPowerDown = false; + state->m_currentPowerMode = DRX_POWER_DOWN; + + state->m_enableParallel = (ulSerialMode == 0); + + state->m_rfmirror = (ulRfMirror == 0); + state->m_IfAgcPol = false; + return 0; +} + +static int DRXX_Open(struct drxk_state *state) +{ + int status = 0; + u32 jtag = 0; + u16 bid = 0; + u16 key = 0; + + dprintk(1, "\n"); + /* stop lock indicator process */ + status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE); + if (status < 0) + goto error; + /* Check device id */ + status = read16(state, SIO_TOP_COMM_KEY__A, &key); + if (status < 0) + goto error; + status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY); + if (status < 0) + goto error; + status = read32(state, SIO_TOP_JTAGID_LO__A, &jtag); + if (status < 0) + goto error; + status = read16(state, SIO_PDR_UIO_IN_HI__A, &bid); + if (status < 0) + goto error; + status = write16(state, SIO_TOP_COMM_KEY__A, key); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int GetDeviceCapabilities(struct drxk_state *state) +{ + u16 sioPdrOhwCfg = 0; + u32 sioTopJtagidLo = 0; + int status; + const char *spin = ""; + + dprintk(1, "\n"); + + /* driver 0.9.0 */ + /* stop lock indicator process */ + status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE); + if (status < 0) + goto error; + status = write16(state, SIO_TOP_COMM_KEY__A, 0xFABA); + if (status < 0) + goto error; + status = read16(state, SIO_PDR_OHW_CFG__A, &sioPdrOhwCfg); + if (status < 0) + goto error; + status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000); + if (status < 0) + goto error; + + switch ((sioPdrOhwCfg & SIO_PDR_OHW_CFG_FREF_SEL__M)) { + case 0: + /* ignore (bypass ?) */ + break; + case 1: + /* 27 MHz */ + state->m_oscClockFreq = 27000; + break; + case 2: + /* 20.25 MHz */ + state->m_oscClockFreq = 20250; + break; + case 3: + /* 4 MHz */ + state->m_oscClockFreq = 20250; + break; + default: + printk(KERN_ERR "drxk: Clock Frequency is unkonwn\n"); + return -EINVAL; + } + /* + Determine device capabilities + Based on pinning v14 + */ + status = read32(state, SIO_TOP_JTAGID_LO__A, &sioTopJtagidLo); + if (status < 0) + goto error; + /* driver 0.9.0 */ + switch ((sioTopJtagidLo >> 29) & 0xF) { + case 0: + state->m_deviceSpin = DRXK_SPIN_A1; + spin = "A1"; + break; + case 2: + state->m_deviceSpin = DRXK_SPIN_A2; + spin = "A2"; + break; + case 3: + state->m_deviceSpin = DRXK_SPIN_A3; + spin = "A3"; + break; + default: + state->m_deviceSpin = DRXK_SPIN_UNKNOWN; + status = -EINVAL; + printk(KERN_ERR "drxk: Spin unknown\n"); + goto error2; + } + switch ((sioTopJtagidLo >> 12) & 0xFF) { + case 0x13: + /* typeId = DRX3913K_TYPE_ID */ + state->m_hasLNA = false; + state->m_hasOOB = false; + state->m_hasATV = false; + state->m_hasAudio = false; + state->m_hasDVBT = true; + state->m_hasDVBC = true; + state->m_hasSAWSW = true; + state->m_hasGPIO2 = false; + state->m_hasGPIO1 = false; + state->m_hasIRQN = false; + break; + case 0x15: + /* typeId = DRX3915K_TYPE_ID */ + state->m_hasLNA = false; + state->m_hasOOB = false; + state->m_hasATV = true; + state->m_hasAudio = false; + state->m_hasDVBT = true; + state->m_hasDVBC = false; + state->m_hasSAWSW = true; + state->m_hasGPIO2 = true; + state->m_hasGPIO1 = true; + state->m_hasIRQN = false; + break; + case 0x16: + /* typeId = DRX3916K_TYPE_ID */ + state->m_hasLNA = false; + state->m_hasOOB = false; + state->m_hasATV = true; + state->m_hasAudio = false; + state->m_hasDVBT = true; + state->m_hasDVBC = false; + state->m_hasSAWSW = true; + state->m_hasGPIO2 = true; + state->m_hasGPIO1 = true; + state->m_hasIRQN = false; + break; + case 0x18: + /* typeId = DRX3918K_TYPE_ID */ + state->m_hasLNA = false; + state->m_hasOOB = false; + state->m_hasATV = true; + state->m_hasAudio = true; + state->m_hasDVBT = true; + state->m_hasDVBC = false; + state->m_hasSAWSW = true; + state->m_hasGPIO2 = true; + state->m_hasGPIO1 = true; + state->m_hasIRQN = false; + break; + case 0x21: + /* typeId = DRX3921K_TYPE_ID */ + state->m_hasLNA = false; + state->m_hasOOB = false; + state->m_hasATV = true; + state->m_hasAudio = true; + state->m_hasDVBT = true; + state->m_hasDVBC = true; + state->m_hasSAWSW = true; + state->m_hasGPIO2 = true; + state->m_hasGPIO1 = true; + state->m_hasIRQN = false; + break; + case 0x23: + /* typeId = DRX3923K_TYPE_ID */ + state->m_hasLNA = false; + state->m_hasOOB = false; + state->m_hasATV = true; + state->m_hasAudio = true; + state->m_hasDVBT = true; + state->m_hasDVBC = true; + state->m_hasSAWSW = true; + state->m_hasGPIO2 = true; + state->m_hasGPIO1 = true; + state->m_hasIRQN = false; + break; + case 0x25: + /* typeId = DRX3925K_TYPE_ID */ + state->m_hasLNA = false; + state->m_hasOOB = false; + state->m_hasATV = true; + state->m_hasAudio = true; + state->m_hasDVBT = true; + state->m_hasDVBC = true; + state->m_hasSAWSW = true; + state->m_hasGPIO2 = true; + state->m_hasGPIO1 = true; + state->m_hasIRQN = false; + break; + case 0x26: + /* typeId = DRX3926K_TYPE_ID */ + state->m_hasLNA = false; + state->m_hasOOB = false; + state->m_hasATV = true; + state->m_hasAudio = false; + state->m_hasDVBT = true; + state->m_hasDVBC = true; + state->m_hasSAWSW = true; + state->m_hasGPIO2 = true; + state->m_hasGPIO1 = true; + state->m_hasIRQN = false; + break; + default: + printk(KERN_ERR "drxk: DeviceID 0x%02x not supported\n", + ((sioTopJtagidLo >> 12) & 0xFF)); + status = -EINVAL; + goto error2; + } + + printk(KERN_INFO + "drxk: detected a drx-39%02xk, spin %s, xtal %d.%03d MHz\n", + ((sioTopJtagidLo >> 12) & 0xFF), spin, + state->m_oscClockFreq / 1000, + state->m_oscClockFreq % 1000); + +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + +error2: + return status; +} + +static int HI_Command(struct drxk_state *state, u16 cmd, u16 *pResult) +{ + int status; + bool powerdown_cmd; + + dprintk(1, "\n"); + + /* Write command */ + status = write16(state, SIO_HI_RA_RAM_CMD__A, cmd); + if (status < 0) + goto error; + if (cmd == SIO_HI_RA_RAM_CMD_RESET) + msleep(1); + + powerdown_cmd = + (bool) ((cmd == SIO_HI_RA_RAM_CMD_CONFIG) && + ((state->m_HICfgCtrl) & + SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M) == + SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ); + if (powerdown_cmd == false) { + /* Wait until command rdy */ + u32 retryCount = 0; + u16 waitCmd; + + do { + msleep(1); + retryCount += 1; + status = read16(state, SIO_HI_RA_RAM_CMD__A, + &waitCmd); + } while ((status < 0) && (retryCount < DRXK_MAX_RETRIES) + && (waitCmd != 0)); + if (status < 0) + goto error; + status = read16(state, SIO_HI_RA_RAM_RES__A, pResult); + } +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + + return status; +} + +static int HI_CfgCommand(struct drxk_state *state) +{ + int status; + + dprintk(1, "\n"); + + mutex_lock(&state->mutex); + + status = write16(state, SIO_HI_RA_RAM_PAR_6__A, state->m_HICfgTimeout); + if (status < 0) + goto error; + status = write16(state, SIO_HI_RA_RAM_PAR_5__A, state->m_HICfgCtrl); + if (status < 0) + goto error; + status = write16(state, SIO_HI_RA_RAM_PAR_4__A, state->m_HICfgWakeUpKey); + if (status < 0) + goto error; + status = write16(state, SIO_HI_RA_RAM_PAR_3__A, state->m_HICfgBridgeDelay); + if (status < 0) + goto error; + status = write16(state, SIO_HI_RA_RAM_PAR_2__A, state->m_HICfgTimingDiv); + if (status < 0) + goto error; + status = write16(state, SIO_HI_RA_RAM_PAR_1__A, SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY); + if (status < 0) + goto error; + status = HI_Command(state, SIO_HI_RA_RAM_CMD_CONFIG, 0); + if (status < 0) + goto error; + + state->m_HICfgCtrl &= ~SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ; +error: + mutex_unlock(&state->mutex); + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int InitHI(struct drxk_state *state) +{ + dprintk(1, "\n"); + + state->m_HICfgWakeUpKey = (state->demod_address << 1); + state->m_HICfgTimeout = 0x96FF; + /* port/bridge/power down ctrl */ + state->m_HICfgCtrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE; + + return HI_CfgCommand(state); +} + +static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable) +{ + int status = -1; + u16 sioPdrMclkCfg = 0; + u16 sioPdrMdxCfg = 0; + + dprintk(1, "\n"); + + /* stop lock indicator process */ + status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE); + if (status < 0) + goto error; + + /* MPEG TS pad configuration */ + status = write16(state, SIO_TOP_COMM_KEY__A, 0xFABA); + if (status < 0) + goto error; + + if (mpegEnable == false) { + /* Set MPEG TS pads to inputmode */ + status = write16(state, SIO_PDR_MSTRT_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MERR_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MCLK_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MVAL_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD0_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD1_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD2_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD3_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD4_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD5_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD6_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD7_CFG__A, 0x0000); + if (status < 0) + goto error; + } else { + /* Enable MPEG output */ + sioPdrMdxCfg = + ((state->m_TSDataStrength << + SIO_PDR_MD0_CFG_DRIVE__B) | 0x0003); + sioPdrMclkCfg = ((state->m_TSClockkStrength << + SIO_PDR_MCLK_CFG_DRIVE__B) | + 0x0003); + + status = write16(state, SIO_PDR_MSTRT_CFG__A, sioPdrMdxCfg); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MERR_CFG__A, 0x0000); /* Disable */ + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MVAL_CFG__A, 0x0000); /* Disable */ + if (status < 0) + goto error; + if (state->m_enableParallel == true) { + /* paralel -> enable MD1 to MD7 */ + status = write16(state, SIO_PDR_MD1_CFG__A, sioPdrMdxCfg); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD2_CFG__A, sioPdrMdxCfg); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD3_CFG__A, sioPdrMdxCfg); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD4_CFG__A, sioPdrMdxCfg); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD5_CFG__A, sioPdrMdxCfg); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD6_CFG__A, sioPdrMdxCfg); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD7_CFG__A, sioPdrMdxCfg); + if (status < 0) + goto error; + } else { + sioPdrMdxCfg = ((state->m_TSDataStrength << + SIO_PDR_MD0_CFG_DRIVE__B) + | 0x0003); + /* serial -> disable MD1 to MD7 */ + status = write16(state, SIO_PDR_MD1_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD2_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD3_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD4_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD5_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD6_CFG__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD7_CFG__A, 0x0000); + if (status < 0) + goto error; + } + status = write16(state, SIO_PDR_MCLK_CFG__A, sioPdrMclkCfg); + if (status < 0) + goto error; + status = write16(state, SIO_PDR_MD0_CFG__A, sioPdrMdxCfg); + if (status < 0) + goto error; + } + /* Enable MB output over MPEG pads and ctl input */ + status = write16(state, SIO_PDR_MON_CFG__A, 0x0000); + if (status < 0) + goto error; + /* Write nomagic word to enable pdr reg write */ + status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int MPEGTSDisable(struct drxk_state *state) +{ + dprintk(1, "\n"); + + return MPEGTSConfigurePins(state, false); +} + +static int BLChainCmd(struct drxk_state *state, + u16 romOffset, u16 nrOfElements, u32 timeOut) +{ + u16 blStatus = 0; + int status; + unsigned long end; + + dprintk(1, "\n"); + mutex_lock(&state->mutex); + status = write16(state, SIO_BL_MODE__A, SIO_BL_MODE_CHAIN); + if (status < 0) + goto error; + status = write16(state, SIO_BL_CHAIN_ADDR__A, romOffset); + if (status < 0) + goto error; + status = write16(state, SIO_BL_CHAIN_LEN__A, nrOfElements); + if (status < 0) + goto error; + status = write16(state, SIO_BL_ENABLE__A, SIO_BL_ENABLE_ON); + if (status < 0) + goto error; + + end = jiffies + msecs_to_jiffies(timeOut); + do { + msleep(1); + status = read16(state, SIO_BL_STATUS__A, &blStatus); + if (status < 0) + goto error; + } while ((blStatus == 0x1) && + ((time_is_after_jiffies(end)))); + + if (blStatus == 0x1) { + printk(KERN_ERR "drxk: SIO not ready\n"); + status = -EINVAL; + goto error2; + } +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); +error2: + mutex_unlock(&state->mutex); + return status; +} + + +static int DownloadMicrocode(struct drxk_state *state, + const u8 pMCImage[], u32 Length) +{ + const u8 *pSrc = pMCImage; + u16 Flags; + u16 Drain; + u32 Address; + u16 nBlocks; + u16 BlockSize; + u16 BlockCRC; + u32 offset = 0; + u32 i; + int status = 0; + + dprintk(1, "\n"); + + /* down the drain (we don care about MAGIC_WORD) */ + Drain = (pSrc[0] << 8) | pSrc[1]; + pSrc += sizeof(u16); + offset += sizeof(u16); + nBlocks = (pSrc[0] << 8) | pSrc[1]; + pSrc += sizeof(u16); + offset += sizeof(u16); + + for (i = 0; i < nBlocks; i += 1) { + Address = (pSrc[0] << 24) | (pSrc[1] << 16) | + (pSrc[2] << 8) | pSrc[3]; + pSrc += sizeof(u32); + offset += sizeof(u32); + + BlockSize = ((pSrc[0] << 8) | pSrc[1]) * sizeof(u16); + pSrc += sizeof(u16); + offset += sizeof(u16); + + Flags = (pSrc[0] << 8) | pSrc[1]; + pSrc += sizeof(u16); + offset += sizeof(u16); + + BlockCRC = (pSrc[0] << 8) | pSrc[1]; + pSrc += sizeof(u16); + offset += sizeof(u16); + + if (offset + BlockSize > Length) { + printk(KERN_ERR "drxk: Firmware is corrupted.\n"); + return -EINVAL; + } + + status = write_block(state, Address, BlockSize, pSrc); + if (status < 0) { + printk(KERN_ERR "drxk: Error %d while loading firmware\n", status); + break; + } + pSrc += BlockSize; + offset += BlockSize; + } + return status; +} + +static int DVBTEnableOFDMTokenRing(struct drxk_state *state, bool enable) +{ + int status; + u16 data = 0; + u16 desiredCtrl = SIO_OFDM_SH_OFDM_RING_ENABLE_ON; + u16 desiredStatus = SIO_OFDM_SH_OFDM_RING_STATUS_ENABLED; + unsigned long end; + + dprintk(1, "\n"); + + if (enable == false) { + desiredCtrl = SIO_OFDM_SH_OFDM_RING_ENABLE_OFF; + desiredStatus = SIO_OFDM_SH_OFDM_RING_STATUS_DOWN; + } + + status = read16(state, SIO_OFDM_SH_OFDM_RING_STATUS__A, &data); + if (status >= 0 && data == desiredStatus) { + /* tokenring already has correct status */ + return status; + } + /* Disable/enable dvbt tokenring bridge */ + status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, desiredCtrl); + + end = jiffies + msecs_to_jiffies(DRXK_OFDM_TR_SHUTDOWN_TIMEOUT); + do { + status = read16(state, SIO_OFDM_SH_OFDM_RING_STATUS__A, &data); + if ((status >= 0 && data == desiredStatus) || time_is_after_jiffies(end)) + break; + msleep(1); + } while (1); + if (data != desiredStatus) { + printk(KERN_ERR "drxk: SIO not ready\n"); + return -EINVAL; + } + return status; +} + +static int MPEGTSStop(struct drxk_state *state) +{ + int status = 0; + u16 fecOcSncMode = 0; + u16 fecOcIprMode = 0; + + dprintk(1, "\n"); + + /* Gracefull shutdown (byte boundaries) */ + status = read16(state, FEC_OC_SNC_MODE__A, &fecOcSncMode); + if (status < 0) + goto error; + fecOcSncMode |= FEC_OC_SNC_MODE_SHUTDOWN__M; + status = write16(state, FEC_OC_SNC_MODE__A, fecOcSncMode); + if (status < 0) + goto error; + + /* Suppress MCLK during absence of data */ + status = read16(state, FEC_OC_IPR_MODE__A, &fecOcIprMode); + if (status < 0) + goto error; + fecOcIprMode |= FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__M; + status = write16(state, FEC_OC_IPR_MODE__A, fecOcIprMode); + +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + + return status; +} + +static int scu_command(struct drxk_state *state, + u16 cmd, u8 parameterLen, + u16 *parameter, u8 resultLen, u16 *result) +{ +#if (SCU_RAM_PARAM_0__A - SCU_RAM_PARAM_15__A) != 15 +#error DRXK register mapping no longer compatible with this routine! +#endif + u16 curCmd = 0; + int status = -EINVAL; + unsigned long end; + u8 buffer[34]; + int cnt = 0, ii; + const char *p; + char errname[30]; + + dprintk(1, "\n"); + + if ((cmd == 0) || ((parameterLen > 0) && (parameter == NULL)) || + ((resultLen > 0) && (result == NULL))) + goto error; + + mutex_lock(&state->mutex); + + /* assume that the command register is ready + since it is checked afterwards */ + for (ii = parameterLen - 1; ii >= 0; ii -= 1) { + buffer[cnt++] = (parameter[ii] & 0xFF); + buffer[cnt++] = ((parameter[ii] >> 8) & 0xFF); + } + buffer[cnt++] = (cmd & 0xFF); + buffer[cnt++] = ((cmd >> 8) & 0xFF); + + write_block(state, SCU_RAM_PARAM_0__A - + (parameterLen - 1), cnt, buffer); + /* Wait until SCU has processed command */ + end = jiffies + msecs_to_jiffies(DRXK_MAX_WAITTIME); + do { + msleep(1); + status = read16(state, SCU_RAM_COMMAND__A, &curCmd); + if (status < 0) + goto error; + } while (!(curCmd == DRX_SCU_READY) && (time_is_after_jiffies(end))); + if (curCmd != DRX_SCU_READY) { + printk(KERN_ERR "drxk: SCU not ready\n"); + status = -EIO; + goto error2; + } + /* read results */ + if ((resultLen > 0) && (result != NULL)) { + s16 err; + int ii; + + for (ii = resultLen - 1; ii >= 0; ii -= 1) { + status = read16(state, SCU_RAM_PARAM_0__A - ii, &result[ii]); + if (status < 0) + goto error; + } + + /* Check if an error was reported by SCU */ + err = (s16)result[0]; + if (err >= 0) + goto error; + + /* check for the known error codes */ + switch (err) { + case SCU_RESULT_UNKCMD: + p = "SCU_RESULT_UNKCMD"; + break; + case SCU_RESULT_UNKSTD: + p = "SCU_RESULT_UNKSTD"; + break; + case SCU_RESULT_SIZE: + p = "SCU_RESULT_SIZE"; + break; + case SCU_RESULT_INVPAR: + p = "SCU_RESULT_INVPAR"; + break; + default: /* Other negative values are errors */ + sprintf(errname, "ERROR: %d\n", err); + p = errname; + } + printk(KERN_ERR "drxk: %s while sending cmd 0x%04x with params:", p, cmd); + print_hex_dump_bytes("drxk: ", DUMP_PREFIX_NONE, buffer, cnt); + status = -EINVAL; + goto error2; + } + +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); +error2: + mutex_unlock(&state->mutex); + return status; +} + +static int SetIqmAf(struct drxk_state *state, bool active) +{ + u16 data = 0; + int status; + + dprintk(1, "\n"); + + /* Configure IQM */ + status = read16(state, IQM_AF_STDBY__A, &data); + if (status < 0) + goto error; + + if (!active) { + data |= (IQM_AF_STDBY_STDBY_ADC_STANDBY + | IQM_AF_STDBY_STDBY_AMP_STANDBY + | IQM_AF_STDBY_STDBY_PD_STANDBY + | IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY + | IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY); + } else { + data &= ((~IQM_AF_STDBY_STDBY_ADC_STANDBY) + & (~IQM_AF_STDBY_STDBY_AMP_STANDBY) + & (~IQM_AF_STDBY_STDBY_PD_STANDBY) + & (~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY) + & (~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY) + ); + } + status = write16(state, IQM_AF_STDBY__A, data); + +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int CtrlPowerMode(struct drxk_state *state, enum DRXPowerMode *mode) +{ + int status = 0; + u16 sioCcPwdMode = 0; + + dprintk(1, "\n"); + + /* Check arguments */ + if (mode == NULL) + return -EINVAL; + + switch (*mode) { + case DRX_POWER_UP: + sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_NONE; + break; + case DRXK_POWER_DOWN_OFDM: + sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_OFDM; + break; + case DRXK_POWER_DOWN_CORE: + sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_CLOCK; + break; + case DRXK_POWER_DOWN_PLL: + sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_PLL; + break; + case DRX_POWER_DOWN: + sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_OSC; + break; + default: + /* Unknow sleep mode */ + return -EINVAL; + } + + /* If already in requested power mode, do nothing */ + if (state->m_currentPowerMode == *mode) + return 0; + + /* For next steps make sure to start from DRX_POWER_UP mode */ + if (state->m_currentPowerMode != DRX_POWER_UP) { + status = PowerUpDevice(state); + if (status < 0) + goto error; + status = DVBTEnableOFDMTokenRing(state, true); + if (status < 0) + goto error; + } + + if (*mode == DRX_POWER_UP) { + /* Restore analog & pin configuartion */ + } else { + /* Power down to requested mode */ + /* Backup some register settings */ + /* Set pins with possible pull-ups connected + to them in input mode */ + /* Analog power down */ + /* ADC power down */ + /* Power down device */ + /* stop all comm_exec */ + /* Stop and power down previous standard */ + switch (state->m_OperationMode) { + case OM_DVBT: + status = MPEGTSStop(state); + if (status < 0) + goto error; + status = PowerDownDVBT(state, false); + if (status < 0) + goto error; + break; + case OM_QAM_ITU_A: + case OM_QAM_ITU_C: + status = MPEGTSStop(state); + if (status < 0) + goto error; + status = PowerDownQAM(state); + if (status < 0) + goto error; + break; + default: + break; + } + status = DVBTEnableOFDMTokenRing(state, false); + if (status < 0) + goto error; + status = write16(state, SIO_CC_PWD_MODE__A, sioCcPwdMode); + if (status < 0) + goto error; + status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY); + if (status < 0) + goto error; + + if (*mode != DRXK_POWER_DOWN_OFDM) { + state->m_HICfgCtrl |= + SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ; + status = HI_CfgCommand(state); + if (status < 0) + goto error; + } + } + state->m_currentPowerMode = *mode; + +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + + return status; +} + +static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode) +{ + enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM; + u16 cmdResult = 0; + u16 data = 0; + int status; + + dprintk(1, "\n"); + + status = read16(state, SCU_COMM_EXEC__A, &data); + if (status < 0) + goto error; + if (data == SCU_COMM_EXEC_ACTIVE) { + /* Send OFDM stop command */ + status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult); + if (status < 0) + goto error; + /* Send OFDM reset command */ + status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult); + if (status < 0) + goto error; + } + + /* Reset datapath for OFDM, processors first */ + status = write16(state, OFDM_SC_COMM_EXEC__A, OFDM_SC_COMM_EXEC_STOP); + if (status < 0) + goto error; + status = write16(state, OFDM_LC_COMM_EXEC__A, OFDM_LC_COMM_EXEC_STOP); + if (status < 0) + goto error; + status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_STOP); + if (status < 0) + goto error; + + /* powerdown AFE */ + status = SetIqmAf(state, false); + if (status < 0) + goto error; + + /* powerdown to OFDM mode */ + if (setPowerMode) { + status = CtrlPowerMode(state, &powerMode); + if (status < 0) + goto error; + } +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int SetOperationMode(struct drxk_state *state, + enum OperationMode oMode) +{ + int status = 0; + + dprintk(1, "\n"); + /* + Stop and power down previous standard + TODO investigate total power down instead of partial + power down depending on "previous" standard. + */ + + /* disable HW lock indicator */ + status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE); + if (status < 0) + goto error; + + /* Device is already at the required mode */ + if (state->m_OperationMode == oMode) + return 0; + + switch (state->m_OperationMode) { + /* OM_NONE was added for start up */ + case OM_NONE: + break; + case OM_DVBT: + status = MPEGTSStop(state); + if (status < 0) + goto error; + status = PowerDownDVBT(state, true); + if (status < 0) + goto error; + state->m_OperationMode = OM_NONE; + break; + case OM_QAM_ITU_A: /* fallthrough */ + case OM_QAM_ITU_C: + status = MPEGTSStop(state); + if (status < 0) + goto error; + status = PowerDownQAM(state); + if (status < 0) + goto error; + state->m_OperationMode = OM_NONE; + break; + case OM_QAM_ITU_B: + default: + status = -EINVAL; + goto error; + } + + /* + Power up new standard + */ + switch (oMode) { + case OM_DVBT: + state->m_OperationMode = oMode; + status = SetDVBTStandard(state, oMode); + if (status < 0) + goto error; + break; + case OM_QAM_ITU_A: /* fallthrough */ + case OM_QAM_ITU_C: + state->m_OperationMode = oMode; + status = SetQAMStandard(state, oMode); + if (status < 0) + goto error; + break; + case OM_QAM_ITU_B: + default: + status = -EINVAL; + } +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int Start(struct drxk_state *state, s32 offsetFreq, + s32 IntermediateFrequency) +{ + int status = -EINVAL; + + u16 IFreqkHz; + s32 OffsetkHz = offsetFreq / 1000; + + dprintk(1, "\n"); + if (state->m_DrxkState != DRXK_STOPPED && + state->m_DrxkState != DRXK_DTV_STARTED) + goto error; + + state->m_bMirrorFreqSpect = (state->param.inversion == INVERSION_ON); + + if (IntermediateFrequency < 0) { + state->m_bMirrorFreqSpect = !state->m_bMirrorFreqSpect; + IntermediateFrequency = -IntermediateFrequency; + } + + switch (state->m_OperationMode) { + case OM_QAM_ITU_A: + case OM_QAM_ITU_C: + IFreqkHz = (IntermediateFrequency / 1000); + status = SetQAM(state, IFreqkHz, OffsetkHz); + if (status < 0) + goto error; + state->m_DrxkState = DRXK_DTV_STARTED; + break; + case OM_DVBT: + IFreqkHz = (IntermediateFrequency / 1000); + status = MPEGTSStop(state); + if (status < 0) + goto error; + status = SetDVBT(state, IFreqkHz, OffsetkHz); + if (status < 0) + goto error; + status = DVBTStart(state); + if (status < 0) + goto error; + state->m_DrxkState = DRXK_DTV_STARTED; + break; + default: + break; + } +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int ShutDown(struct drxk_state *state) +{ + dprintk(1, "\n"); + + MPEGTSStop(state); + return 0; +} + +static int GetLockStatus(struct drxk_state *state, u32 *pLockStatus, + u32 Time) +{ + int status = -EINVAL; + + dprintk(1, "\n"); + + if (pLockStatus == NULL) + goto error; + + *pLockStatus = NOT_LOCKED; + + /* define the SCU command code */ + switch (state->m_OperationMode) { + case OM_QAM_ITU_A: + case OM_QAM_ITU_B: + case OM_QAM_ITU_C: + status = GetQAMLockStatus(state, pLockStatus); + break; + case OM_DVBT: + status = GetDVBTLockStatus(state, pLockStatus); + break; + default: + break; + } +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int MPEGTSStart(struct drxk_state *state) +{ + int status; + + u16 fecOcSncMode = 0; + + /* Allow OC to sync again */ + status = read16(state, FEC_OC_SNC_MODE__A, &fecOcSncMode); + if (status < 0) + goto error; + fecOcSncMode &= ~FEC_OC_SNC_MODE_SHUTDOWN__M; + status = write16(state, FEC_OC_SNC_MODE__A, fecOcSncMode); + if (status < 0) + goto error; + status = write16(state, FEC_OC_SNC_UNLOCK__A, 1); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int MPEGTSDtoInit(struct drxk_state *state) +{ + int status; + + dprintk(1, "\n"); + + /* Rate integration settings */ + status = write16(state, FEC_OC_RCN_CTL_STEP_LO__A, 0x0000); + if (status < 0) + goto error; + status = write16(state, FEC_OC_RCN_CTL_STEP_HI__A, 0x000C); + if (status < 0) + goto error; + status = write16(state, FEC_OC_RCN_GAIN__A, 0x000A); + if (status < 0) + goto error; + status = write16(state, FEC_OC_AVR_PARM_A__A, 0x0008); + if (status < 0) + goto error; + status = write16(state, FEC_OC_AVR_PARM_B__A, 0x0006); + if (status < 0) + goto error; + status = write16(state, FEC_OC_TMD_HI_MARGIN__A, 0x0680); + if (status < 0) + goto error; + status = write16(state, FEC_OC_TMD_LO_MARGIN__A, 0x0080); + if (status < 0) + goto error; + status = write16(state, FEC_OC_TMD_COUNT__A, 0x03F4); + if (status < 0) + goto error; + + /* Additional configuration */ + status = write16(state, FEC_OC_OCR_INVERT__A, 0); + if (status < 0) + goto error; + status = write16(state, FEC_OC_SNC_LWM__A, 2); + if (status < 0) + goto error; + status = write16(state, FEC_OC_SNC_HWM__A, 12); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + + return status; +} + +static int MPEGTSDtoSetup(struct drxk_state *state, + enum OperationMode oMode) +{ + int status; + + u16 fecOcRegMode = 0; /* FEC_OC_MODE register value */ + u16 fecOcRegIprMode = 0; /* FEC_OC_IPR_MODE register value */ + u16 fecOcDtoMode = 0; /* FEC_OC_IPR_INVERT register value */ + u16 fecOcFctMode = 0; /* FEC_OC_IPR_INVERT register value */ + u16 fecOcDtoPeriod = 2; /* FEC_OC_IPR_INVERT register value */ + u16 fecOcDtoBurstLen = 188; /* FEC_OC_IPR_INVERT register value */ + u32 fecOcRcnCtlRate = 0; /* FEC_OC_IPR_INVERT register value */ + u16 fecOcTmdMode = 0; + u16 fecOcTmdIntUpdRate = 0; + u32 maxBitRate = 0; + bool staticCLK = false; + + dprintk(1, "\n"); + + /* Check insertion of the Reed-Solomon parity bytes */ + status = read16(state, FEC_OC_MODE__A, &fecOcRegMode); + if (status < 0) + goto error; + status = read16(state, FEC_OC_IPR_MODE__A, &fecOcRegIprMode); + if (status < 0) + goto error; + fecOcRegMode &= (~FEC_OC_MODE_PARITY__M); + fecOcRegIprMode &= (~FEC_OC_IPR_MODE_MVAL_DIS_PAR__M); + if (state->m_insertRSByte == true) { + /* enable parity symbol forward */ + fecOcRegMode |= FEC_OC_MODE_PARITY__M; + /* MVAL disable during parity bytes */ + fecOcRegIprMode |= FEC_OC_IPR_MODE_MVAL_DIS_PAR__M; + /* TS burst length to 204 */ + fecOcDtoBurstLen = 204; + } + + /* Check serial or parrallel output */ + fecOcRegIprMode &= (~(FEC_OC_IPR_MODE_SERIAL__M)); + if (state->m_enableParallel == false) { + /* MPEG data output is serial -> set ipr_mode[0] */ + fecOcRegIprMode |= FEC_OC_IPR_MODE_SERIAL__M; + } + + switch (oMode) { + case OM_DVBT: + maxBitRate = state->m_DVBTBitrate; + fecOcTmdMode = 3; + fecOcRcnCtlRate = 0xC00000; + staticCLK = state->m_DVBTStaticCLK; + break; + case OM_QAM_ITU_A: /* fallthrough */ + case OM_QAM_ITU_C: + fecOcTmdMode = 0x0004; + fecOcRcnCtlRate = 0xD2B4EE; /* good for >63 Mb/s */ + maxBitRate = state->m_DVBCBitrate; + staticCLK = state->m_DVBCStaticCLK; + break; + default: + status = -EINVAL; + } /* switch (standard) */ + if (status < 0) + goto error; + + /* Configure DTO's */ + if (staticCLK) { + u32 bitRate = 0; + + /* Rational DTO for MCLK source (static MCLK rate), + Dynamic DTO for optimal grouping + (avoid intra-packet gaps), + DTO offset enable to sync TS burst with MSTRT */ + fecOcDtoMode = (FEC_OC_DTO_MODE_DYNAMIC__M | + FEC_OC_DTO_MODE_OFFSET_ENABLE__M); + fecOcFctMode = (FEC_OC_FCT_MODE_RAT_ENA__M | + FEC_OC_FCT_MODE_VIRT_ENA__M); + + /* Check user defined bitrate */ + bitRate = maxBitRate; + if (bitRate > 75900000UL) { /* max is 75.9 Mb/s */ + bitRate = 75900000UL; + } + /* Rational DTO period: + dto_period = (Fsys / bitrate) - 2 + + Result should be floored, + to make sure >= requested bitrate + */ + fecOcDtoPeriod = (u16) (((state->m_sysClockFreq) + * 1000) / bitRate); + if (fecOcDtoPeriod <= 2) + fecOcDtoPeriod = 0; + else + fecOcDtoPeriod -= 2; + fecOcTmdIntUpdRate = 8; + } else { + /* (commonAttr->staticCLK == false) => dynamic mode */ + fecOcDtoMode = FEC_OC_DTO_MODE_DYNAMIC__M; + fecOcFctMode = FEC_OC_FCT_MODE__PRE; + fecOcTmdIntUpdRate = 5; + } + + /* Write appropriate registers with requested configuration */ + status = write16(state, FEC_OC_DTO_BURST_LEN__A, fecOcDtoBurstLen); + if (status < 0) + goto error; + status = write16(state, FEC_OC_DTO_PERIOD__A, fecOcDtoPeriod); + if (status < 0) + goto error; + status = write16(state, FEC_OC_DTO_MODE__A, fecOcDtoMode); + if (status < 0) + goto error; + status = write16(state, FEC_OC_FCT_MODE__A, fecOcFctMode); + if (status < 0) + goto error; + status = write16(state, FEC_OC_MODE__A, fecOcRegMode); + if (status < 0) + goto error; + status = write16(state, FEC_OC_IPR_MODE__A, fecOcRegIprMode); + if (status < 0) + goto error; + + /* Rate integration settings */ + status = write32(state, FEC_OC_RCN_CTL_RATE_LO__A, fecOcRcnCtlRate); + if (status < 0) + goto error; + status = write16(state, FEC_OC_TMD_INT_UPD_RATE__A, fecOcTmdIntUpdRate); + if (status < 0) + goto error; + status = write16(state, FEC_OC_TMD_MODE__A, fecOcTmdMode); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int MPEGTSConfigurePolarity(struct drxk_state *state) +{ + u16 fecOcRegIprInvert = 0; + + /* Data mask for the output data byte */ + u16 InvertDataMask = + FEC_OC_IPR_INVERT_MD7__M | FEC_OC_IPR_INVERT_MD6__M | + FEC_OC_IPR_INVERT_MD5__M | FEC_OC_IPR_INVERT_MD4__M | + FEC_OC_IPR_INVERT_MD3__M | FEC_OC_IPR_INVERT_MD2__M | + FEC_OC_IPR_INVERT_MD1__M | FEC_OC_IPR_INVERT_MD0__M; + + dprintk(1, "\n"); + + /* Control selective inversion of output bits */ + fecOcRegIprInvert &= (~(InvertDataMask)); + if (state->m_invertDATA == true) + fecOcRegIprInvert |= InvertDataMask; + fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MERR__M)); + if (state->m_invertERR == true) + fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MERR__M; + fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MSTRT__M)); + if (state->m_invertSTR == true) + fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MSTRT__M; + fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MVAL__M)); + if (state->m_invertVAL == true) + fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MVAL__M; + fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MCLK__M)); + if (state->m_invertCLK == true) + fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MCLK__M; + + return write16(state, FEC_OC_IPR_INVERT__A, fecOcRegIprInvert); +} + +#define SCU_RAM_AGC_KI_INV_RF_POL__M 0x4000 + +static int SetAgcRf(struct drxk_state *state, + struct SCfgAgc *pAgcCfg, bool isDTV) +{ + int status = -EINVAL; + u16 data = 0; + struct SCfgAgc *pIfAgcSettings; + + dprintk(1, "\n"); + + if (pAgcCfg == NULL) + goto error; + + switch (pAgcCfg->ctrlMode) { + case DRXK_AGC_CTRL_AUTO: + /* Enable RF AGC DAC */ + status = read16(state, IQM_AF_STDBY__A, &data); + if (status < 0) + goto error; + data &= ~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY; + status = write16(state, IQM_AF_STDBY__A, data); + if (status < 0) + goto error; + status = read16(state, SCU_RAM_AGC_CONFIG__A, &data); + if (status < 0) + goto error; + + /* Enable SCU RF AGC loop */ + data &= ~SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M; + + /* Polarity */ + if (state->m_RfAgcPol) + data |= SCU_RAM_AGC_CONFIG_INV_RF_POL__M; + else + data &= ~SCU_RAM_AGC_CONFIG_INV_RF_POL__M; + status = write16(state, SCU_RAM_AGC_CONFIG__A, data); + if (status < 0) + goto error; + + /* Set speed (using complementary reduction value) */ + status = read16(state, SCU_RAM_AGC_KI_RED__A, &data); + if (status < 0) + goto error; + + data &= ~SCU_RAM_AGC_KI_RED_RAGC_RED__M; + data |= (~(pAgcCfg->speed << + SCU_RAM_AGC_KI_RED_RAGC_RED__B) + & SCU_RAM_AGC_KI_RED_RAGC_RED__M); + + status = write16(state, SCU_RAM_AGC_KI_RED__A, data); + if (status < 0) + goto error; + + if (IsDVBT(state)) + pIfAgcSettings = &state->m_dvbtIfAgcCfg; + else if (IsQAM(state)) + pIfAgcSettings = &state->m_qamIfAgcCfg; + else + pIfAgcSettings = &state->m_atvIfAgcCfg; + if (pIfAgcSettings == NULL) { + status = -EINVAL; + goto error; + } + + /* Set TOP, only if IF-AGC is in AUTO mode */ + if (pIfAgcSettings->ctrlMode == DRXK_AGC_CTRL_AUTO) + status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pAgcCfg->top); + if (status < 0) + goto error; + + /* Cut-Off current */ + status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, pAgcCfg->cutOffCurrent); + if (status < 0) + goto error; + + /* Max. output level */ + status = write16(state, SCU_RAM_AGC_RF_MAX__A, pAgcCfg->maxOutputLevel); + if (status < 0) + goto error; + + break; + + case DRXK_AGC_CTRL_USER: + /* Enable RF AGC DAC */ + status = read16(state, IQM_AF_STDBY__A, &data); + if (status < 0) + goto error; + data &= ~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY; + status = write16(state, IQM_AF_STDBY__A, data); + if (status < 0) + goto error; + + /* Disable SCU RF AGC loop */ + status = read16(state, SCU_RAM_AGC_CONFIG__A, &data); + if (status < 0) + goto error; + data |= SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M; + if (state->m_RfAgcPol) + data |= SCU_RAM_AGC_CONFIG_INV_RF_POL__M; + else + data &= ~SCU_RAM_AGC_CONFIG_INV_RF_POL__M; + status = write16(state, SCU_RAM_AGC_CONFIG__A, data); + if (status < 0) + goto error; + + /* SCU c.o.c. to 0, enabling full control range */ + status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, 0); + if (status < 0) + goto error; + + /* Write value to output pin */ + status = write16(state, SCU_RAM_AGC_RF_IACCU_HI__A, pAgcCfg->outputLevel); + if (status < 0) + goto error; + break; + + case DRXK_AGC_CTRL_OFF: + /* Disable RF AGC DAC */ + status = read16(state, IQM_AF_STDBY__A, &data); + if (status < 0) + goto error; + data |= IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY; + status = write16(state, IQM_AF_STDBY__A, data); + if (status < 0) + goto error; + + /* Disable SCU RF AGC loop */ + status = read16(state, SCU_RAM_AGC_CONFIG__A, &data); + if (status < 0) + goto error; + data |= SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M; + status = write16(state, SCU_RAM_AGC_CONFIG__A, data); + if (status < 0) + goto error; + break; + + default: + status = -EINVAL; + + } +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +#define SCU_RAM_AGC_KI_INV_IF_POL__M 0x2000 + +static int SetAgcIf(struct drxk_state *state, + struct SCfgAgc *pAgcCfg, bool isDTV) +{ + u16 data = 0; + int status = 0; + struct SCfgAgc *pRfAgcSettings; + + dprintk(1, "\n"); + + switch (pAgcCfg->ctrlMode) { + case DRXK_AGC_CTRL_AUTO: + + /* Enable IF AGC DAC */ + status = read16(state, IQM_AF_STDBY__A, &data); + if (status < 0) + goto error; + data &= ~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY; + status = write16(state, IQM_AF_STDBY__A, data); + if (status < 0) + goto error; + + status = read16(state, SCU_RAM_AGC_CONFIG__A, &data); + if (status < 0) + goto error; + + /* Enable SCU IF AGC loop */ + data &= ~SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M; + + /* Polarity */ + if (state->m_IfAgcPol) + data |= SCU_RAM_AGC_CONFIG_INV_IF_POL__M; + else + data &= ~SCU_RAM_AGC_CONFIG_INV_IF_POL__M; + status = write16(state, SCU_RAM_AGC_CONFIG__A, data); + if (status < 0) + goto error; + + /* Set speed (using complementary reduction value) */ + status = read16(state, SCU_RAM_AGC_KI_RED__A, &data); + if (status < 0) + goto error; + data &= ~SCU_RAM_AGC_KI_RED_IAGC_RED__M; + data |= (~(pAgcCfg->speed << + SCU_RAM_AGC_KI_RED_IAGC_RED__B) + & SCU_RAM_AGC_KI_RED_IAGC_RED__M); + + status = write16(state, SCU_RAM_AGC_KI_RED__A, data); + if (status < 0) + goto error; + + if (IsQAM(state)) + pRfAgcSettings = &state->m_qamRfAgcCfg; + else + pRfAgcSettings = &state->m_atvRfAgcCfg; + if (pRfAgcSettings == NULL) + return -1; + /* Restore TOP */ + status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pRfAgcSettings->top); + if (status < 0) + goto error; + break; + + case DRXK_AGC_CTRL_USER: + + /* Enable IF AGC DAC */ + status = read16(state, IQM_AF_STDBY__A, &data); + if (status < 0) + goto error; + data &= ~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY; + status = write16(state, IQM_AF_STDBY__A, data); + if (status < 0) + goto error; + + status = read16(state, SCU_RAM_AGC_CONFIG__A, &data); + if (status < 0) + goto error; + + /* Disable SCU IF AGC loop */ + data |= SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M; + + /* Polarity */ + if (state->m_IfAgcPol) + data |= SCU_RAM_AGC_CONFIG_INV_IF_POL__M; + else + data &= ~SCU_RAM_AGC_CONFIG_INV_IF_POL__M; + status = write16(state, SCU_RAM_AGC_CONFIG__A, data); + if (status < 0) + goto error; + + /* Write value to output pin */ + status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pAgcCfg->outputLevel); + if (status < 0) + goto error; + break; + + case DRXK_AGC_CTRL_OFF: + + /* Disable If AGC DAC */ + status = read16(state, IQM_AF_STDBY__A, &data); + if (status < 0) + goto error; + data |= IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY; + status = write16(state, IQM_AF_STDBY__A, data); + if (status < 0) + goto error; + + /* Disable SCU IF AGC loop */ + status = read16(state, SCU_RAM_AGC_CONFIG__A, &data); + if (status < 0) + goto error; + data |= SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M; + status = write16(state, SCU_RAM_AGC_CONFIG__A, data); + if (status < 0) + goto error; + break; + } /* switch (agcSettingsIf->ctrlMode) */ + + /* always set the top to support + configurations without if-loop */ + status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, pAgcCfg->top); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int ReadIFAgc(struct drxk_state *state, u32 *pValue) +{ + u16 agcDacLvl; + int status; + u16 Level = 0; + + dprintk(1, "\n"); + + status = read16(state, IQM_AF_AGC_IF__A, &agcDacLvl); + if (status < 0) { + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; + } + + *pValue = 0; + + if (agcDacLvl > DRXK_AGC_DAC_OFFSET) + Level = agcDacLvl - DRXK_AGC_DAC_OFFSET; + if (Level < 14000) + *pValue = (14000 - Level) / 4; + else + *pValue = 0; + + return status; +} + +static int GetQAMSignalToNoise(struct drxk_state *state, + s32 *pSignalToNoise) +{ + int status = 0; + u16 qamSlErrPower = 0; /* accum. error between + raw and sliced symbols */ + u32 qamSlSigPower = 0; /* used for MER, depends of + QAM constellation */ + u32 qamSlMer = 0; /* QAM MER */ + + dprintk(1, "\n"); + + /* MER calculation */ + + /* get the register value needed for MER */ + status = read16(state, QAM_SL_ERR_POWER__A, &qamSlErrPower); + if (status < 0) { + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return -EINVAL; + } + + switch (state->param.u.qam.modulation) { + case QAM_16: + qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM16 << 2; + break; + case QAM_32: + qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM32 << 2; + break; + case QAM_64: + qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM64 << 2; + break; + case QAM_128: + qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM128 << 2; + break; + default: + case QAM_256: + qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM256 << 2; + break; + } + + if (qamSlErrPower > 0) { + qamSlMer = Log10Times100(qamSlSigPower) - + Log10Times100((u32) qamSlErrPower); + } + *pSignalToNoise = qamSlMer; + + return status; +} + +static int GetDVBTSignalToNoise(struct drxk_state *state, + s32 *pSignalToNoise) +{ + int status; + u16 regData = 0; + u32 EqRegTdSqrErrI = 0; + u32 EqRegTdSqrErrQ = 0; + u16 EqRegTdSqrErrExp = 0; + u16 EqRegTdTpsPwrOfs = 0; + u16 EqRegTdReqSmbCnt = 0; + u32 tpsCnt = 0; + u32 SqrErrIQ = 0; + u32 a = 0; + u32 b = 0; + u32 c = 0; + u32 iMER = 0; + u16 transmissionParams = 0; + + dprintk(1, "\n"); + + status = read16(state, OFDM_EQ_TOP_TD_TPS_PWR_OFS__A, &EqRegTdTpsPwrOfs); + if (status < 0) + goto error; + status = read16(state, OFDM_EQ_TOP_TD_REQ_SMB_CNT__A, &EqRegTdReqSmbCnt); + if (status < 0) + goto error; + status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_EXP__A, &EqRegTdSqrErrExp); + if (status < 0) + goto error; + status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_I__A, ®Data); + if (status < 0) + goto error; + /* Extend SQR_ERR_I operational range */ + EqRegTdSqrErrI = (u32) regData; + if ((EqRegTdSqrErrExp > 11) && + (EqRegTdSqrErrI < 0x00000FFFUL)) { + EqRegTdSqrErrI += 0x00010000UL; + } + status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_Q__A, ®Data); + if (status < 0) + goto error; + /* Extend SQR_ERR_Q operational range */ + EqRegTdSqrErrQ = (u32) regData; + if ((EqRegTdSqrErrExp > 11) && + (EqRegTdSqrErrQ < 0x00000FFFUL)) + EqRegTdSqrErrQ += 0x00010000UL; + + status = read16(state, OFDM_SC_RA_RAM_OP_PARAM__A, &transmissionParams); + if (status < 0) + goto error; + + /* Check input data for MER */ + + /* MER calculation (in 0.1 dB) without math.h */ + if ((EqRegTdTpsPwrOfs == 0) || (EqRegTdReqSmbCnt == 0)) + iMER = 0; + else if ((EqRegTdSqrErrI + EqRegTdSqrErrQ) == 0) { + /* No error at all, this must be the HW reset value + * Apparently no first measurement yet + * Set MER to 0.0 */ + iMER = 0; + } else { + SqrErrIQ = (EqRegTdSqrErrI + EqRegTdSqrErrQ) << + EqRegTdSqrErrExp; + if ((transmissionParams & + OFDM_SC_RA_RAM_OP_PARAM_MODE__M) + == OFDM_SC_RA_RAM_OP_PARAM_MODE_2K) + tpsCnt = 17; + else + tpsCnt = 68; + + /* IMER = 100 * log10 (x) + where x = (EqRegTdTpsPwrOfs^2 * + EqRegTdReqSmbCnt * tpsCnt)/SqrErrIQ + + => IMER = a + b -c + where a = 100 * log10 (EqRegTdTpsPwrOfs^2) + b = 100 * log10 (EqRegTdReqSmbCnt * tpsCnt) + c = 100 * log10 (SqrErrIQ) + */ + + /* log(x) x = 9bits * 9bits->18 bits */ + a = Log10Times100(EqRegTdTpsPwrOfs * + EqRegTdTpsPwrOfs); + /* log(x) x = 16bits * 7bits->23 bits */ + b = Log10Times100(EqRegTdReqSmbCnt * tpsCnt); + /* log(x) x = (16bits + 16bits) << 15 ->32 bits */ + c = Log10Times100(SqrErrIQ); + + iMER = a + b; + /* No negative MER, clip to zero */ + if (iMER > c) + iMER -= c; + else + iMER = 0; + } + *pSignalToNoise = iMER; + +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int GetSignalToNoise(struct drxk_state *state, s32 *pSignalToNoise) +{ + dprintk(1, "\n"); + + *pSignalToNoise = 0; + switch (state->m_OperationMode) { + case OM_DVBT: + return GetDVBTSignalToNoise(state, pSignalToNoise); + case OM_QAM_ITU_A: + case OM_QAM_ITU_C: + return GetQAMSignalToNoise(state, pSignalToNoise); + default: + break; + } + return 0; +} + +#if 0 +static int GetDVBTQuality(struct drxk_state *state, s32 *pQuality) +{ + /* SNR Values for quasi errorfree reception rom Nordig 2.2 */ + int status = 0; + + dprintk(1, "\n"); + + static s32 QE_SN[] = { + 51, /* QPSK 1/2 */ + 69, /* QPSK 2/3 */ + 79, /* QPSK 3/4 */ + 89, /* QPSK 5/6 */ + 97, /* QPSK 7/8 */ + 108, /* 16-QAM 1/2 */ + 131, /* 16-QAM 2/3 */ + 146, /* 16-QAM 3/4 */ + 156, /* 16-QAM 5/6 */ + 160, /* 16-QAM 7/8 */ + 165, /* 64-QAM 1/2 */ + 187, /* 64-QAM 2/3 */ + 202, /* 64-QAM 3/4 */ + 216, /* 64-QAM 5/6 */ + 225, /* 64-QAM 7/8 */ + }; + + *pQuality = 0; + + do { + s32 SignalToNoise = 0; + u16 Constellation = 0; + u16 CodeRate = 0; + u32 SignalToNoiseRel; + u32 BERQuality; + + status = GetDVBTSignalToNoise(state, &SignalToNoise); + if (status < 0) + break; + status = read16(state, OFDM_EQ_TOP_TD_TPS_CONST__A, &Constellation); + if (status < 0) + break; + Constellation &= OFDM_EQ_TOP_TD_TPS_CONST__M; + + status = read16(state, OFDM_EQ_TOP_TD_TPS_CODE_HP__A, &CodeRate); + if (status < 0) + break; + CodeRate &= OFDM_EQ_TOP_TD_TPS_CODE_HP__M; + + if (Constellation > OFDM_EQ_TOP_TD_TPS_CONST_64QAM || + CodeRate > OFDM_EQ_TOP_TD_TPS_CODE_LP_7_8) + break; + SignalToNoiseRel = SignalToNoise - + QE_SN[Constellation * 5 + CodeRate]; + BERQuality = 100; + + if (SignalToNoiseRel < -70) + *pQuality = 0; + else if (SignalToNoiseRel < 30) + *pQuality = ((SignalToNoiseRel + 70) * + BERQuality) / 100; + else + *pQuality = BERQuality; + } while (0); + return 0; +}; + +static int GetDVBCQuality(struct drxk_state *state, s32 *pQuality) +{ + int status = 0; + *pQuality = 0; + + dprintk(1, "\n"); + + do { + u32 SignalToNoise = 0; + u32 BERQuality = 100; + u32 SignalToNoiseRel = 0; + + status = GetQAMSignalToNoise(state, &SignalToNoise); + if (status < 0) + break; + + switch (state->param.u.qam.modulation) { + case QAM_16: + SignalToNoiseRel = SignalToNoise - 200; + break; + case QAM_32: + SignalToNoiseRel = SignalToNoise - 230; + break; /* Not in NorDig */ + case QAM_64: + SignalToNoiseRel = SignalToNoise - 260; + break; + case QAM_128: + SignalToNoiseRel = SignalToNoise - 290; + break; + default: + case QAM_256: + SignalToNoiseRel = SignalToNoise - 320; + break; + } + + if (SignalToNoiseRel < -70) + *pQuality = 0; + else if (SignalToNoiseRel < 30) + *pQuality = ((SignalToNoiseRel + 70) * + BERQuality) / 100; + else + *pQuality = BERQuality; + } while (0); + + return status; +} + +static int GetQuality(struct drxk_state *state, s32 *pQuality) +{ + dprintk(1, "\n"); + + switch (state->m_OperationMode) { + case OM_DVBT: + return GetDVBTQuality(state, pQuality); + case OM_QAM_ITU_A: + return GetDVBCQuality(state, pQuality); + default: + break; + } + + return 0; +} +#endif + +/* Free data ram in SIO HI */ +#define SIO_HI_RA_RAM_USR_BEGIN__A 0x420040 +#define SIO_HI_RA_RAM_USR_END__A 0x420060 + +#define DRXK_HI_ATOMIC_BUF_START (SIO_HI_RA_RAM_USR_BEGIN__A) +#define DRXK_HI_ATOMIC_BUF_END (SIO_HI_RA_RAM_USR_BEGIN__A + 7) +#define DRXK_HI_ATOMIC_READ SIO_HI_RA_RAM_PAR_3_ACP_RW_READ +#define DRXK_HI_ATOMIC_WRITE SIO_HI_RA_RAM_PAR_3_ACP_RW_WRITE + +#define DRXDAP_FASI_ADDR2BLOCK(addr) (((addr) >> 22) & 0x3F) +#define DRXDAP_FASI_ADDR2BANK(addr) (((addr) >> 16) & 0x3F) +#define DRXDAP_FASI_ADDR2OFFSET(addr) ((addr) & 0x7FFF) + +static int ConfigureI2CBridge(struct drxk_state *state, bool bEnableBridge) +{ + int status = -EINVAL; + + dprintk(1, "\n"); + + if (state->m_DrxkState == DRXK_UNINITIALIZED) + goto error; + if (state->m_DrxkState == DRXK_POWERED_DOWN) + goto error; + + if (state->no_i2c_bridge) + return 0; + + status = write16(state, SIO_HI_RA_RAM_PAR_1__A, SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY); + if (status < 0) + goto error; + if (bEnableBridge) { + status = write16(state, SIO_HI_RA_RAM_PAR_2__A, SIO_HI_RA_RAM_PAR_2_BRD_CFG_CLOSED); + if (status < 0) + goto error; + } else { + status = write16(state, SIO_HI_RA_RAM_PAR_2__A, SIO_HI_RA_RAM_PAR_2_BRD_CFG_OPEN); + if (status < 0) + goto error; + } + + status = HI_Command(state, SIO_HI_RA_RAM_CMD_BRDCTRL, 0); + +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int SetPreSaw(struct drxk_state *state, + struct SCfgPreSaw *pPreSawCfg) +{ + int status = -EINVAL; + + dprintk(1, "\n"); + + if ((pPreSawCfg == NULL) + || (pPreSawCfg->reference > IQM_AF_PDREF__M)) + goto error; + + status = write16(state, IQM_AF_PDREF__A, pPreSawCfg->reference); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int BLDirectCmd(struct drxk_state *state, u32 targetAddr, + u16 romOffset, u16 nrOfElements, u32 timeOut) +{ + u16 blStatus = 0; + u16 offset = (u16) ((targetAddr >> 0) & 0x00FFFF); + u16 blockbank = (u16) ((targetAddr >> 16) & 0x000FFF); + int status; + unsigned long end; + + dprintk(1, "\n"); + + mutex_lock(&state->mutex); + status = write16(state, SIO_BL_MODE__A, SIO_BL_MODE_DIRECT); + if (status < 0) + goto error; + status = write16(state, SIO_BL_TGT_HDR__A, blockbank); + if (status < 0) + goto error; + status = write16(state, SIO_BL_TGT_ADDR__A, offset); + if (status < 0) + goto error; + status = write16(state, SIO_BL_SRC_ADDR__A, romOffset); + if (status < 0) + goto error; + status = write16(state, SIO_BL_SRC_LEN__A, nrOfElements); + if (status < 0) + goto error; + status = write16(state, SIO_BL_ENABLE__A, SIO_BL_ENABLE_ON); + if (status < 0) + goto error; + + end = jiffies + msecs_to_jiffies(timeOut); + do { + status = read16(state, SIO_BL_STATUS__A, &blStatus); + if (status < 0) + goto error; + } while ((blStatus == 0x1) && time_is_after_jiffies(end)); + if (blStatus == 0x1) { + printk(KERN_ERR "drxk: SIO not ready\n"); + status = -EINVAL; + goto error2; + } +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); +error2: + mutex_unlock(&state->mutex); + return status; + +} + +static int ADCSyncMeasurement(struct drxk_state *state, u16 *count) +{ + u16 data = 0; + int status; + + dprintk(1, "\n"); + + /* Start measurement */ + status = write16(state, IQM_AF_COMM_EXEC__A, IQM_AF_COMM_EXEC_ACTIVE); + if (status < 0) + goto error; + status = write16(state, IQM_AF_START_LOCK__A, 1); + if (status < 0) + goto error; + + *count = 0; + status = read16(state, IQM_AF_PHASE0__A, &data); + if (status < 0) + goto error; + if (data == 127) + *count = *count + 1; + status = read16(state, IQM_AF_PHASE1__A, &data); + if (status < 0) + goto error; + if (data == 127) + *count = *count + 1; + status = read16(state, IQM_AF_PHASE2__A, &data); + if (status < 0) + goto error; + if (data == 127) + *count = *count + 1; + +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int ADCSynchronization(struct drxk_state *state) +{ + u16 count = 0; + int status; + + dprintk(1, "\n"); + + status = ADCSyncMeasurement(state, &count); + if (status < 0) + goto error; + + if (count == 1) { + /* Try sampling on a diffrent edge */ + u16 clkNeg = 0; + + status = read16(state, IQM_AF_CLKNEG__A, &clkNeg); + if (status < 0) + goto error; + if ((clkNeg | IQM_AF_CLKNEG_CLKNEGDATA__M) == + IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS) { + clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M)); + clkNeg |= + IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_NEG; + } else { + clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M)); + clkNeg |= + IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS; + } + status = write16(state, IQM_AF_CLKNEG__A, clkNeg); + if (status < 0) + goto error; + status = ADCSyncMeasurement(state, &count); + if (status < 0) + goto error; + } + + if (count < 2) + status = -EINVAL; +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int SetFrequencyShifter(struct drxk_state *state, + u16 intermediateFreqkHz, + s32 tunerFreqOffset, bool isDTV) +{ + bool selectPosImage = false; + u32 rfFreqResidual = tunerFreqOffset; + u32 fmFrequencyShift = 0; + bool tunerMirror = !state->m_bMirrorFreqSpect; + u32 adcFreq; + bool adcFlip; + int status; + u32 ifFreqActual; + u32 samplingFrequency = (u32) (state->m_sysClockFreq / 3); + u32 frequencyShift; + bool imageToSelect; + + dprintk(1, "\n"); + + /* + Program frequency shifter + No need to account for mirroring on RF + */ + if (isDTV) { + if ((state->m_OperationMode == OM_QAM_ITU_A) || + (state->m_OperationMode == OM_QAM_ITU_C) || + (state->m_OperationMode == OM_DVBT)) + selectPosImage = true; + else + selectPosImage = false; + } + if (tunerMirror) + /* tuner doesn't mirror */ + ifFreqActual = intermediateFreqkHz + + rfFreqResidual + fmFrequencyShift; + else + /* tuner mirrors */ + ifFreqActual = intermediateFreqkHz - + rfFreqResidual - fmFrequencyShift; + if (ifFreqActual > samplingFrequency / 2) { + /* adc mirrors */ + adcFreq = samplingFrequency - ifFreqActual; + adcFlip = true; + } else { + /* adc doesn't mirror */ + adcFreq = ifFreqActual; + adcFlip = false; + } + + frequencyShift = adcFreq; + imageToSelect = state->m_rfmirror ^ tunerMirror ^ + adcFlip ^ selectPosImage; + state->m_IqmFsRateOfs = + Frac28a((frequencyShift), samplingFrequency); + + if (imageToSelect) + state->m_IqmFsRateOfs = ~state->m_IqmFsRateOfs + 1; + + /* Program frequency shifter with tuner offset compensation */ + /* frequencyShift += tunerFreqOffset; TODO */ + status = write32(state, IQM_FS_RATE_OFS_LO__A, + state->m_IqmFsRateOfs); + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int InitAGC(struct drxk_state *state, bool isDTV) +{ + u16 ingainTgt = 0; + u16 ingainTgtMin = 0; + u16 ingainTgtMax = 0; + u16 clpCyclen = 0; + u16 clpSumMin = 0; + u16 clpDirTo = 0; + u16 snsSumMin = 0; + u16 snsSumMax = 0; + u16 clpSumMax = 0; + u16 snsDirTo = 0; + u16 kiInnergainMin = 0; + u16 ifIaccuHiTgt = 0; + u16 ifIaccuHiTgtMin = 0; + u16 ifIaccuHiTgtMax = 0; + u16 data = 0; + u16 fastClpCtrlDelay = 0; + u16 clpCtrlMode = 0; + int status = 0; + + dprintk(1, "\n"); + + /* Common settings */ + snsSumMax = 1023; + ifIaccuHiTgtMin = 2047; + clpCyclen = 500; + clpSumMax = 1023; + + /* AGCInit() not available for DVBT; init done in microcode */ + if (!IsQAM(state)) { + printk(KERN_ERR "drxk: %s: mode %d is not DVB-C\n", __func__, state->m_OperationMode); + return -EINVAL; + } + + /* FIXME: Analog TV AGC require different settings */ + + /* Standard specific settings */ + clpSumMin = 8; + clpDirTo = (u16) -9; + clpCtrlMode = 0; + snsSumMin = 8; + snsDirTo = (u16) -9; + kiInnergainMin = (u16) -1030; + ifIaccuHiTgtMax = 0x2380; + ifIaccuHiTgt = 0x2380; + ingainTgtMin = 0x0511; + ingainTgt = 0x0511; + ingainTgtMax = 5119; + fastClpCtrlDelay = state->m_qamIfAgcCfg.FastClipCtrlDelay; + + status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A, fastClpCtrlDelay); + if (status < 0) + goto error; + + status = write16(state, SCU_RAM_AGC_CLP_CTRL_MODE__A, clpCtrlMode); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_INGAIN_TGT__A, ingainTgt); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, ingainTgtMin); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A, ingainTgtMax); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__A, ifIaccuHiTgtMin); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, ifIaccuHiTgtMax); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_IF_IACCU_HI__A, 0); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_IF_IACCU_LO__A, 0); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_RF_IACCU_HI__A, 0); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_RF_IACCU_LO__A, 0); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_CLP_SUM_MAX__A, clpSumMax); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_SNS_SUM_MAX__A, snsSumMax); + if (status < 0) + goto error; + + status = write16(state, SCU_RAM_AGC_KI_INNERGAIN_MIN__A, kiInnergainMin); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT__A, ifIaccuHiTgt); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_CLP_CYCLEN__A, clpCyclen); + if (status < 0) + goto error; + + status = write16(state, SCU_RAM_AGC_RF_SNS_DEV_MAX__A, 1023); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_RF_SNS_DEV_MIN__A, (u16) -1023); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_FAST_SNS_CTRL_DELAY__A, 50); + if (status < 0) + goto error; + + status = write16(state, SCU_RAM_AGC_KI_MAXMINGAIN_TH__A, 20); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_CLP_SUM_MIN__A, clpSumMin); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_SNS_SUM_MIN__A, snsSumMin); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_CLP_DIR_TO__A, clpDirTo); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_SNS_DIR_TO__A, snsDirTo); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_KI_MINGAIN__A, 0x7fff); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_KI_MAXGAIN__A, 0x0); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_KI_MIN__A, 0x0117); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_KI_MAX__A, 0x0657); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_CLP_SUM__A, 0); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_CLP_CYCCNT__A, 0); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_CLP_DIR_WD__A, 0); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_CLP_DIR_STP__A, 1); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_SNS_SUM__A, 0); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_SNS_CYCCNT__A, 0); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_SNS_DIR_WD__A, 0); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_SNS_DIR_STP__A, 1); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_SNS_CYCLEN__A, 500); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_KI_CYCLEN__A, 500); + if (status < 0) + goto error; + + /* Initialize inner-loop KI gain factors */ + status = read16(state, SCU_RAM_AGC_KI__A, &data); + if (status < 0) + goto error; + + data = 0x0657; + data &= ~SCU_RAM_AGC_KI_RF__M; + data |= (DRXK_KI_RAGC_QAM << SCU_RAM_AGC_KI_RF__B); + data &= ~SCU_RAM_AGC_KI_IF__M; + data |= (DRXK_KI_IAGC_QAM << SCU_RAM_AGC_KI_IF__B); + + status = write16(state, SCU_RAM_AGC_KI__A, data); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int DVBTQAMGetAccPktErr(struct drxk_state *state, u16 *packetErr) +{ + int status; + + dprintk(1, "\n"); + if (packetErr == NULL) + status = write16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, 0); + else + status = read16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, packetErr); + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int DVBTScCommand(struct drxk_state *state, + u16 cmd, u16 subcmd, + u16 param0, u16 param1, u16 param2, + u16 param3, u16 param4) +{ + u16 curCmd = 0; + u16 errCode = 0; + u16 retryCnt = 0; + u16 scExec = 0; + int status; + + dprintk(1, "\n"); + status = read16(state, OFDM_SC_COMM_EXEC__A, &scExec); + if (scExec != 1) { + /* SC is not running */ + status = -EINVAL; + } + if (status < 0) + goto error; + + /* Wait until sc is ready to receive command */ + retryCnt = 0; + do { + msleep(1); + status = read16(state, OFDM_SC_RA_RAM_CMD__A, &curCmd); + retryCnt++; + } while ((curCmd != 0) && (retryCnt < DRXK_MAX_RETRIES)); + if (retryCnt >= DRXK_MAX_RETRIES && (status < 0)) + goto error; + + /* Write sub-command */ + switch (cmd) { + /* All commands using sub-cmd */ + case OFDM_SC_RA_RAM_CMD_PROC_START: + case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM: + case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM: + status = write16(state, OFDM_SC_RA_RAM_CMD_ADDR__A, subcmd); + if (status < 0) + goto error; + break; + default: + /* Do nothing */ + break; + } + + /* Write needed parameters and the command */ + switch (cmd) { + /* All commands using 5 parameters */ + /* All commands using 4 parameters */ + /* All commands using 3 parameters */ + /* All commands using 2 parameters */ + case OFDM_SC_RA_RAM_CMD_PROC_START: + case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM: + case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM: + status = write16(state, OFDM_SC_RA_RAM_PARAM1__A, param1); + /* All commands using 1 parameters */ + case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING: + case OFDM_SC_RA_RAM_CMD_USER_IO: + status = write16(state, OFDM_SC_RA_RAM_PARAM0__A, param0); + /* All commands using 0 parameters */ + case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM: + case OFDM_SC_RA_RAM_CMD_NULL: + /* Write command */ + status = write16(state, OFDM_SC_RA_RAM_CMD__A, cmd); + break; + default: + /* Unknown command */ + status = -EINVAL; + } + if (status < 0) + goto error; + + /* Wait until sc is ready processing command */ + retryCnt = 0; + do { + msleep(1); + status = read16(state, OFDM_SC_RA_RAM_CMD__A, &curCmd); + retryCnt++; + } while ((curCmd != 0) && (retryCnt < DRXK_MAX_RETRIES)); + if (retryCnt >= DRXK_MAX_RETRIES && (status < 0)) + goto error; + + /* Check for illegal cmd */ + status = read16(state, OFDM_SC_RA_RAM_CMD_ADDR__A, &errCode); + if (errCode == 0xFFFF) { + /* illegal command */ + status = -EINVAL; + } + if (status < 0) + goto error; + + /* Retreive results parameters from SC */ + switch (cmd) { + /* All commands yielding 5 results */ + /* All commands yielding 4 results */ + /* All commands yielding 3 results */ + /* All commands yielding 2 results */ + /* All commands yielding 1 result */ + case OFDM_SC_RA_RAM_CMD_USER_IO: + case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM: + status = read16(state, OFDM_SC_RA_RAM_PARAM0__A, &(param0)); + /* All commands yielding 0 results */ + case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING: + case OFDM_SC_RA_RAM_CMD_SET_TIMER: + case OFDM_SC_RA_RAM_CMD_PROC_START: + case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM: + case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM: + case OFDM_SC_RA_RAM_CMD_NULL: + break; + default: + /* Unknown command */ + status = -EINVAL; + break; + } /* switch (cmd->cmd) */ +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int PowerUpDVBT(struct drxk_state *state) +{ + enum DRXPowerMode powerMode = DRX_POWER_UP; + int status; + + dprintk(1, "\n"); + status = CtrlPowerMode(state, &powerMode); + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int DVBTCtrlSetIncEnable(struct drxk_state *state, bool *enabled) +{ + int status; + + dprintk(1, "\n"); + if (*enabled == true) + status = write16(state, IQM_CF_BYPASSDET__A, 0); + else + status = write16(state, IQM_CF_BYPASSDET__A, 1); + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +#define DEFAULT_FR_THRES_8K 4000 +static int DVBTCtrlSetFrEnable(struct drxk_state *state, bool *enabled) +{ + + int status; + + dprintk(1, "\n"); + if (*enabled == true) { + /* write mask to 1 */ + status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A, + DEFAULT_FR_THRES_8K); + } else { + /* write mask to 0 */ + status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A, 0); + } + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + + return status; +} + +static int DVBTCtrlSetEchoThreshold(struct drxk_state *state, + struct DRXKCfgDvbtEchoThres_t *echoThres) +{ + u16 data = 0; + int status; + + dprintk(1, "\n"); + status = read16(state, OFDM_SC_RA_RAM_ECHO_THRES__A, &data); + if (status < 0) + goto error; + + switch (echoThres->fftMode) { + case DRX_FFTMODE_2K: + data &= ~OFDM_SC_RA_RAM_ECHO_THRES_2K__M; + data |= ((echoThres->threshold << + OFDM_SC_RA_RAM_ECHO_THRES_2K__B) + & (OFDM_SC_RA_RAM_ECHO_THRES_2K__M)); + break; + case DRX_FFTMODE_8K: + data &= ~OFDM_SC_RA_RAM_ECHO_THRES_8K__M; + data |= ((echoThres->threshold << + OFDM_SC_RA_RAM_ECHO_THRES_8K__B) + & (OFDM_SC_RA_RAM_ECHO_THRES_8K__M)); + break; + default: + return -EINVAL; + } + + status = write16(state, OFDM_SC_RA_RAM_ECHO_THRES__A, data); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int DVBTCtrlSetSqiSpeed(struct drxk_state *state, + enum DRXKCfgDvbtSqiSpeed *speed) +{ + int status = -EINVAL; + + dprintk(1, "\n"); + + switch (*speed) { + case DRXK_DVBT_SQI_SPEED_FAST: + case DRXK_DVBT_SQI_SPEED_MEDIUM: + case DRXK_DVBT_SQI_SPEED_SLOW: + break; + default: + goto error; + } + status = write16(state, SCU_RAM_FEC_PRE_RS_BER_FILTER_SH__A, + (u16) *speed); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +/*============================================================================*/ + +/** +* \brief Activate DVBT specific presets +* \param demod instance of demodulator. +* \return DRXStatus_t. +* +* Called in DVBTSetStandard +* +*/ +static int DVBTActivatePresets(struct drxk_state *state) +{ + int status; + bool setincenable = false; + bool setfrenable = true; + + struct DRXKCfgDvbtEchoThres_t echoThres2k = { 0, DRX_FFTMODE_2K }; + struct DRXKCfgDvbtEchoThres_t echoThres8k = { 0, DRX_FFTMODE_8K }; + + dprintk(1, "\n"); + status = DVBTCtrlSetIncEnable(state, &setincenable); + if (status < 0) + goto error; + status = DVBTCtrlSetFrEnable(state, &setfrenable); + if (status < 0) + goto error; + status = DVBTCtrlSetEchoThreshold(state, &echoThres2k); + if (status < 0) + goto error; + status = DVBTCtrlSetEchoThreshold(state, &echoThres8k); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A, state->m_dvbtIfAgcCfg.IngainTgtMax); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +/*============================================================================*/ + +/** +* \brief Initialize channelswitch-independent settings for DVBT. +* \param demod instance of demodulator. +* \return DRXStatus_t. +* +* For ROM code channel filter taps are loaded from the bootloader. For microcode +* the DVB-T taps from the drxk_filters.h are used. +*/ +static int SetDVBTStandard(struct drxk_state *state, + enum OperationMode oMode) +{ + u16 cmdResult = 0; + u16 data = 0; + int status; + + dprintk(1, "\n"); + + PowerUpDVBT(state); + /* added antenna switch */ + SwitchAntennaToDVBT(state); + /* send OFDM reset command */ + status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult); + if (status < 0) + goto error; + + /* send OFDM setenv command */ + status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV, 0, NULL, 1, &cmdResult); + if (status < 0) + goto error; + + /* reset datapath for OFDM, processors first */ + status = write16(state, OFDM_SC_COMM_EXEC__A, OFDM_SC_COMM_EXEC_STOP); + if (status < 0) + goto error; + status = write16(state, OFDM_LC_COMM_EXEC__A, OFDM_LC_COMM_EXEC_STOP); + if (status < 0) + goto error; + status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_STOP); + if (status < 0) + goto error; + + /* IQM setup */ + /* synchronize on ofdstate->m_festart */ + status = write16(state, IQM_AF_UPD_SEL__A, 1); + if (status < 0) + goto error; + /* window size for clipping ADC detection */ + status = write16(state, IQM_AF_CLP_LEN__A, 0); + if (status < 0) + goto error; + /* window size for for sense pre-SAW detection */ + status = write16(state, IQM_AF_SNS_LEN__A, 0); + if (status < 0) + goto error; + /* sense threshold for sense pre-SAW detection */ + status = write16(state, IQM_AF_AMUX__A, IQM_AF_AMUX_SIGNAL2ADC); + if (status < 0) + goto error; + status = SetIqmAf(state, true); + if (status < 0) + goto error; + + status = write16(state, IQM_AF_AGC_RF__A, 0); + if (status < 0) + goto error; + + /* Impulse noise cruncher setup */ + status = write16(state, IQM_AF_INC_LCT__A, 0); /* crunch in IQM_CF */ + if (status < 0) + goto error; + status = write16(state, IQM_CF_DET_LCT__A, 0); /* detect in IQM_CF */ + if (status < 0) + goto error; + status = write16(state, IQM_CF_WND_LEN__A, 3); /* peak detector window length */ + if (status < 0) + goto error; + + status = write16(state, IQM_RC_STRETCH__A, 16); + if (status < 0) + goto error; + status = write16(state, IQM_CF_OUT_ENA__A, 0x4); /* enable output 2 */ + if (status < 0) + goto error; + status = write16(state, IQM_CF_DS_ENA__A, 0x4); /* decimate output 2 */ + if (status < 0) + goto error; + status = write16(state, IQM_CF_SCALE__A, 1600); + if (status < 0) + goto error; + status = write16(state, IQM_CF_SCALE_SH__A, 0); + if (status < 0) + goto error; + + /* virtual clipping threshold for clipping ADC detection */ + status = write16(state, IQM_AF_CLP_TH__A, 448); + if (status < 0) + goto error; + status = write16(state, IQM_CF_DATATH__A, 495); /* crunching threshold */ + if (status < 0) + goto error; + + status = BLChainCmd(state, DRXK_BL_ROM_OFFSET_TAPS_DVBT, DRXK_BLCC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT); + if (status < 0) + goto error; + + status = write16(state, IQM_CF_PKDTH__A, 2); /* peak detector threshold */ + if (status < 0) + goto error; + status = write16(state, IQM_CF_POW_MEAS_LEN__A, 2); + if (status < 0) + goto error; + /* enable power measurement interrupt */ + status = write16(state, IQM_CF_COMM_INT_MSK__A, 1); + if (status < 0) + goto error; + status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_ACTIVE); + if (status < 0) + goto error; + + /* IQM will not be reset from here, sync ADC and update/init AGC */ + status = ADCSynchronization(state); + if (status < 0) + goto error; + status = SetPreSaw(state, &state->m_dvbtPreSawCfg); + if (status < 0) + goto error; + + /* Halt SCU to enable safe non-atomic accesses */ + status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD); + if (status < 0) + goto error; + + status = SetAgcRf(state, &state->m_dvbtRfAgcCfg, true); + if (status < 0) + goto error; + status = SetAgcIf(state, &state->m_dvbtIfAgcCfg, true); + if (status < 0) + goto error; + + /* Set Noise Estimation notch width and enable DC fix */ + status = read16(state, OFDM_SC_RA_RAM_CONFIG__A, &data); + if (status < 0) + goto error; + data |= OFDM_SC_RA_RAM_CONFIG_NE_FIX_ENABLE__M; + status = write16(state, OFDM_SC_RA_RAM_CONFIG__A, data); + if (status < 0) + goto error; + + /* Activate SCU to enable SCU commands */ + status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE); + if (status < 0) + goto error; + + if (!state->m_DRXK_A3_ROM_CODE) { + /* AGCInit() is not done for DVBT, so set agcFastClipCtrlDelay */ + status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A, state->m_dvbtIfAgcCfg.FastClipCtrlDelay); + if (status < 0) + goto error; + } + + /* OFDM_SC setup */ +#ifdef COMPILE_FOR_NONRT + status = write16(state, OFDM_SC_RA_RAM_BE_OPT_DELAY__A, 1); + if (status < 0) + goto error; + status = write16(state, OFDM_SC_RA_RAM_BE_OPT_INIT_DELAY__A, 2); + if (status < 0) + goto error; +#endif + + /* FEC setup */ + status = write16(state, FEC_DI_INPUT_CTL__A, 1); /* OFDM input */ + if (status < 0) + goto error; + + +#ifdef COMPILE_FOR_NONRT + status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, 0x400); + if (status < 0) + goto error; +#else + status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, 0x1000); + if (status < 0) + goto error; +#endif + status = write16(state, FEC_RS_MEASUREMENT_PRESCALE__A, 0x0001); + if (status < 0) + goto error; + + /* Setup MPEG bus */ + status = MPEGTSDtoSetup(state, OM_DVBT); + if (status < 0) + goto error; + /* Set DVBT Presets */ + status = DVBTActivatePresets(state); + if (status < 0) + goto error; + +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +/*============================================================================*/ +/** +* \brief Start dvbt demodulating for channel. +* \param demod instance of demodulator. +* \return DRXStatus_t. +*/ +static int DVBTStart(struct drxk_state *state) +{ + u16 param1; + int status; + /* DRXKOfdmScCmd_t scCmd; */ + + dprintk(1, "\n"); + /* Start correct processes to get in lock */ + /* DRXK: OFDM_SC_RA_RAM_PROC_LOCKTRACK is no longer in mapfile! */ + param1 = OFDM_SC_RA_RAM_LOCKTRACK_MIN; + status = DVBTScCommand(state, OFDM_SC_RA_RAM_CMD_PROC_START, 0, OFDM_SC_RA_RAM_SW_EVENT_RUN_NMASK__M, param1, 0, 0, 0); + if (status < 0) + goto error; + /* Start FEC OC */ + status = MPEGTSStart(state); + if (status < 0) + goto error; + status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_ACTIVE); + if (status < 0) + goto error; +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + + +/*============================================================================*/ + +/** +* \brief Set up dvbt demodulator for channel. +* \param demod instance of demodulator. +* \return DRXStatus_t. +* // original DVBTSetChannel() +*/ +static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, + s32 tunerFreqOffset) +{ + u16 cmdResult = 0; + u16 transmissionParams = 0; + u16 operationMode = 0; + u32 iqmRcRateOfs = 0; + u32 bandwidth = 0; + u16 param1; + int status; + + dprintk(1, "IF =%d, TFO = %d\n", IntermediateFreqkHz, tunerFreqOffset); + + status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult); + if (status < 0) + goto error; + + /* Halt SCU to enable safe non-atomic accesses */ + status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD); + if (status < 0) + goto error; + + /* Stop processors */ + status = write16(state, OFDM_SC_COMM_EXEC__A, OFDM_SC_COMM_EXEC_STOP); + if (status < 0) + goto error; + status = write16(state, OFDM_LC_COMM_EXEC__A, OFDM_LC_COMM_EXEC_STOP); + if (status < 0) + goto error; + + /* Mandatory fix, always stop CP, required to set spl offset back to + hardware default (is set to 0 by ucode during pilot detection */ + status = write16(state, OFDM_CP_COMM_EXEC__A, OFDM_CP_COMM_EXEC_STOP); + if (status < 0) + goto error; + + /*== Write channel settings to device =====================================*/ + + /* mode */ + switch (state->param.u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_AUTO: + default: + operationMode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M; + /* fall through , try first guess DRX_FFTMODE_8K */ + case TRANSMISSION_MODE_8K: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K; + break; + case TRANSMISSION_MODE_2K: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_2K; + break; + } + + /* guard */ + switch (state->param.u.ofdm.guard_interval) { + default: + case GUARD_INTERVAL_AUTO: + operationMode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M; + /* fall through , try first guess DRX_GUARD_1DIV4 */ + case GUARD_INTERVAL_1_4: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4; + break; + case GUARD_INTERVAL_1_32: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_32; + break; + case GUARD_INTERVAL_1_16: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_16; + break; + case GUARD_INTERVAL_1_8: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_8; + break; + } + + /* hierarchy */ + switch (state->param.u.ofdm.hierarchy_information) { + case HIERARCHY_AUTO: + case HIERARCHY_NONE: + default: + operationMode |= OFDM_SC_RA_RAM_OP_AUTO_HIER__M; + /* fall through , try first guess SC_RA_RAM_OP_PARAM_HIER_NO */ + /* transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_NO; */ + /* break; */ + case HIERARCHY_1: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1; + break; + case HIERARCHY_2: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A2; + break; + case HIERARCHY_4: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A4; + break; + } + + + /* constellation */ + switch (state->param.u.ofdm.constellation) { + case QAM_AUTO: + default: + operationMode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M; + /* fall through , try first guess DRX_CONSTELLATION_QAM64 */ + case QAM_64: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64; + break; + case QPSK: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QPSK; + break; + case QAM_16: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM16; + break; + } +#if 0 + /* No hierachical channels support in BDA */ + /* Priority (only for hierarchical channels) */ + switch (channel->priority) { + case DRX_PRIORITY_LOW: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_LO; + WR16(devAddr, OFDM_EC_SB_PRIOR__A, + OFDM_EC_SB_PRIOR_LO); + break; + case DRX_PRIORITY_HIGH: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI; + WR16(devAddr, OFDM_EC_SB_PRIOR__A, + OFDM_EC_SB_PRIOR_HI)); + break; + case DRX_PRIORITY_UNKNOWN: /* fall through */ + default: + status = -EINVAL; + goto error; + } +#else + /* Set Priorty high */ + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI; + status = write16(state, OFDM_EC_SB_PRIOR__A, OFDM_EC_SB_PRIOR_HI); + if (status < 0) + goto error; +#endif + + /* coderate */ + switch (state->param.u.ofdm.code_rate_HP) { + case FEC_AUTO: + default: + operationMode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M; + /* fall through , try first guess DRX_CODERATE_2DIV3 */ + case FEC_2_3: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3; + break; + case FEC_1_2: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_1_2; + break; + case FEC_3_4: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_3_4; + break; + case FEC_5_6: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_5_6; + break; + case FEC_7_8: + transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_7_8; + break; + } + + /* SAW filter selection: normaly not necesarry, but if wanted + the application can select a SAW filter via the driver by using UIOs */ + /* First determine real bandwidth (Hz) */ + /* Also set delay for impulse noise cruncher */ + /* Also set parameters for EC_OC fix, note EC_OC_REG_TMD_HIL_MAR is changed + by SC for fix for some 8K,1/8 guard but is restored by InitEC and ResetEC + functions */ + switch (state->param.u.ofdm.bandwidth) { + case BANDWIDTH_AUTO: + case BANDWIDTH_8_MHZ: + bandwidth = DRXK_BANDWIDTH_8MHZ_IN_HZ; + status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3052); + if (status < 0) + goto error; + /* cochannel protection for PAL 8 MHz */ + status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 7); + if (status < 0) + goto error; + status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 7); + if (status < 0) + goto error; + status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 7); + if (status < 0) + goto error; + status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1); + if (status < 0) + goto error; + break; + case BANDWIDTH_7_MHZ: + bandwidth = DRXK_BANDWIDTH_7MHZ_IN_HZ; + status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3491); + if (status < 0) + goto error; + /* cochannel protection for PAL 7 MHz */ + status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 8); + if (status < 0) + goto error; + status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 8); + if (status < 0) + goto error; + status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 4); + if (status < 0) + goto error; + status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1); + if (status < 0) + goto error; + break; + case BANDWIDTH_6_MHZ: + bandwidth = DRXK_BANDWIDTH_6MHZ_IN_HZ; + status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 4073); + if (status < 0) + goto error; + /* cochannel protection for NTSC 6 MHz */ + status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 19); + if (status < 0) + goto error; + status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 19); + if (status < 0) + goto error; + status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 14); + if (status < 0) + goto error; + status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1); + if (status < 0) + goto error; + break; + default: + status = -EINVAL; + goto error; + } + + if (iqmRcRateOfs == 0) { + /* Now compute IQM_RC_RATE_OFS + (((SysFreq/BandWidth)/2)/2) -1) * 2^23) + => + ((SysFreq / BandWidth) * (2^21)) - (2^23) + */ + /* (SysFreq / BandWidth) * (2^28) */ + /* assert (MAX(sysClk)/MIN(bandwidth) < 16) + => assert(MAX(sysClk) < 16*MIN(bandwidth)) + => assert(109714272 > 48000000) = true so Frac 28 can be used */ + iqmRcRateOfs = Frac28a((u32) + ((state->m_sysClockFreq * + 1000) / 3), bandwidth); + /* (SysFreq / BandWidth) * (2^21), rounding before truncating */ + if ((iqmRcRateOfs & 0x7fL) >= 0x40) + iqmRcRateOfs += 0x80L; + iqmRcRateOfs = iqmRcRateOfs >> 7; + /* ((SysFreq / BandWidth) * (2^21)) - (2^23) */ + iqmRcRateOfs = iqmRcRateOfs - (1 << 23); + } + + iqmRcRateOfs &= + ((((u32) IQM_RC_RATE_OFS_HI__M) << + IQM_RC_RATE_OFS_LO__W) | IQM_RC_RATE_OFS_LO__M); + status = write32(state, IQM_RC_RATE_OFS_LO__A, iqmRcRateOfs); + if (status < 0) + goto error; + + /* Bandwidth setting done */ + +#if 0 + status = DVBTSetFrequencyShift(demod, channel, tunerOffset); + if (status < 0) + goto error; +#endif + status = SetFrequencyShifter(state, IntermediateFreqkHz, tunerFreqOffset, true); + if (status < 0) + goto error; + + /*== Start SC, write channel settings to SC ===============================*/ + + /* Activate SCU to enable SCU commands */ + status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE); + if (status < 0) + goto error; + + /* Enable SC after setting all other parameters */ + status = write16(state, OFDM_SC_COMM_STATE__A, 0); + if (status < 0) + goto error; + status = write16(state, OFDM_SC_COMM_EXEC__A, 1); + if (status < 0) + goto error; + + + status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_START, 0, NULL, 1, &cmdResult); + if (status < 0) + goto error; + + /* Write SC parameter registers, set all AUTO flags in operation mode */ + param1 = (OFDM_SC_RA_RAM_OP_AUTO_MODE__M | + OFDM_SC_RA_RAM_OP_AUTO_GUARD__M | + OFDM_SC_RA_RAM_OP_AUTO_CONST__M | + OFDM_SC_RA_RAM_OP_AUTO_HIER__M | + OFDM_SC_RA_RAM_OP_AUTO_RATE__M); + status = DVBTScCommand(state, OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM, + 0, transmissionParams, param1, 0, 0, 0); + if (status < 0) + goto error; + + if (!state->m_DRXK_A3_ROM_CODE) + status = DVBTCtrlSetSqiSpeed(state, &state->m_sqiSpeed); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + + return status; +} + + +/*============================================================================*/ + +/** +* \brief Retreive lock status . +* \param demod Pointer to demodulator instance. +* \param lockStat Pointer to lock status structure. +* \return DRXStatus_t. +* +*/ +static int GetDVBTLockStatus(struct drxk_state *state, u32 *pLockStatus) +{ + int status; + const u16 mpeg_lock_mask = (OFDM_SC_RA_RAM_LOCK_MPEG__M | + OFDM_SC_RA_RAM_LOCK_FEC__M); + const u16 fec_lock_mask = (OFDM_SC_RA_RAM_LOCK_FEC__M); + const u16 demod_lock_mask = OFDM_SC_RA_RAM_LOCK_DEMOD__M; + + u16 ScRaRamLock = 0; + u16 ScCommExec = 0; + + dprintk(1, "\n"); + + *pLockStatus = NOT_LOCKED; + /* driver 0.9.0 */ + /* Check if SC is running */ + status = read16(state, OFDM_SC_COMM_EXEC__A, &ScCommExec); + if (status < 0) + goto end; + if (ScCommExec == OFDM_SC_COMM_EXEC_STOP) + goto end; + + status = read16(state, OFDM_SC_RA_RAM_LOCK__A, &ScRaRamLock); + if (status < 0) + goto end; + + if ((ScRaRamLock & mpeg_lock_mask) == mpeg_lock_mask) + *pLockStatus = MPEG_LOCK; + else if ((ScRaRamLock & fec_lock_mask) == fec_lock_mask) + *pLockStatus = FEC_LOCK; + else if ((ScRaRamLock & demod_lock_mask) == demod_lock_mask) + *pLockStatus = DEMOD_LOCK; + else if (ScRaRamLock & OFDM_SC_RA_RAM_LOCK_NODVBT__M) + *pLockStatus = NEVER_LOCK; +end: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + + return status; +} + +static int PowerUpQAM(struct drxk_state *state) +{ + enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM; + int status; + + dprintk(1, "\n"); + status = CtrlPowerMode(state, &powerMode); + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + + return status; +} + + +/** Power Down QAM */ +static int PowerDownQAM(struct drxk_state *state) +{ + u16 data = 0; + u16 cmdResult; + int status = 0; + + dprintk(1, "\n"); + status = read16(state, SCU_COMM_EXEC__A, &data); + if (status < 0) + goto error; + if (data == SCU_COMM_EXEC_ACTIVE) { + /* + STOP demodulator + QAM and HW blocks + */ + /* stop all comstate->m_exec */ + status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_STOP); + if (status < 0) + goto error; + status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult); + if (status < 0) + goto error; + } + /* powerdown AFE */ + status = SetIqmAf(state, false); + +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + + return status; +} + +/*============================================================================*/ + +/** +* \brief Setup of the QAM Measurement intervals for signal quality +* \param demod instance of demod. +* \param constellation current constellation. +* \return DRXStatus_t. +* +* NOTE: +* Take into account that for certain settings the errorcounters can overflow. +* The implementation does not check this. +* +*/ +static int SetQAMMeasurement(struct drxk_state *state, + enum EDrxkConstellation constellation, + u32 symbolRate) +{ + u32 fecBitsDesired = 0; /* BER accounting period */ + u32 fecRsPeriodTotal = 0; /* Total period */ + u16 fecRsPrescale = 0; /* ReedSolomon Measurement Prescale */ + u16 fecRsPeriod = 0; /* Value for corresponding I2C register */ + int status = 0; + + dprintk(1, "\n"); + + fecRsPrescale = 1; + /* fecBitsDesired = symbolRate [kHz] * + FrameLenght [ms] * + (constellation + 1) * + SyncLoss (== 1) * + ViterbiLoss (==1) + */ + switch (constellation) { + case DRX_CONSTELLATION_QAM16: + fecBitsDesired = 4 * symbolRate; + break; + case DRX_CONSTELLATION_QAM32: + fecBitsDesired = 5 * symbolRate; + break; + case DRX_CONSTELLATION_QAM64: + fecBitsDesired = 6 * symbolRate; + break; + case DRX_CONSTELLATION_QAM128: + fecBitsDesired = 7 * symbolRate; + break; + case DRX_CONSTELLATION_QAM256: + fecBitsDesired = 8 * symbolRate; + break; + default: + status = -EINVAL; + } + if (status < 0) + goto error; + + fecBitsDesired /= 1000; /* symbolRate [Hz] -> symbolRate [kHz] */ + fecBitsDesired *= 500; /* meas. period [ms] */ + + /* Annex A/C: bits/RsPeriod = 204 * 8 = 1632 */ + /* fecRsPeriodTotal = fecBitsDesired / 1632 */ + fecRsPeriodTotal = (fecBitsDesired / 1632UL) + 1; /* roughly ceil */ + + /* fecRsPeriodTotal = fecRsPrescale * fecRsPeriod */ + fecRsPrescale = 1 + (u16) (fecRsPeriodTotal >> 16); + if (fecRsPrescale == 0) { + /* Divide by zero (though impossible) */ + status = -EINVAL; + if (status < 0) + goto error; + } + fecRsPeriod = + ((u16) fecRsPeriodTotal + + (fecRsPrescale >> 1)) / fecRsPrescale; + + /* write corresponding registers */ + status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, fecRsPeriod); + if (status < 0) + goto error; + status = write16(state, FEC_RS_MEASUREMENT_PRESCALE__A, fecRsPrescale); + if (status < 0) + goto error; + status = write16(state, FEC_OC_SNC_FAIL_PERIOD__A, fecRsPeriod); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int SetQAM16(struct drxk_state *state) +{ + int status = 0; + + dprintk(1, "\n"); + /* QAM Equalizer Setup */ + /* Equalizer */ + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 13517); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 13517); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 13517); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 13517); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 13517); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 13517); + if (status < 0) + goto error; + /* Decision Feedback Equalizer */ + status = write16(state, QAM_DQ_QUAL_FUN0__A, 2); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN1__A, 2); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN2__A, 2); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN3__A, 2); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN4__A, 2); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN5__A, 0); + if (status < 0) + goto error; + + status = write16(state, QAM_SY_SYNC_HWM__A, 5); + if (status < 0) + goto error; + status = write16(state, QAM_SY_SYNC_AWM__A, 4); + if (status < 0) + goto error; + status = write16(state, QAM_SY_SYNC_LWM__A, 3); + if (status < 0) + goto error; + + /* QAM Slicer Settings */ + status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM16); + if (status < 0) + goto error; + + /* QAM Loop Controller Coeficients */ + status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16); + if (status < 0) + goto error; + + status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 20); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 80); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 20); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 50); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 16); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 32); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 10); + if (status < 0) + goto error; + + + /* QAM State Machine (FSM) Thresholds */ + + status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 140); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 50); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 95); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 120); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 230); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 105); + if (status < 0) + goto error; + + status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 24); + if (status < 0) + goto error; + + + /* QAM FSM Tracking Parameters */ + + status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 16); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 220); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 25); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 6); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -24); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -65); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -127); + if (status < 0) + goto error; + +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +/*============================================================================*/ + +/** +* \brief QAM32 specific setup +* \param demod instance of demod. +* \return DRXStatus_t. +*/ +static int SetQAM32(struct drxk_state *state) +{ + int status = 0; + + dprintk(1, "\n"); + + /* QAM Equalizer Setup */ + /* Equalizer */ + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 6707); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 6707); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 6707); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 6707); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 6707); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 6707); + if (status < 0) + goto error; + + /* Decision Feedback Equalizer */ + status = write16(state, QAM_DQ_QUAL_FUN0__A, 3); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN1__A, 3); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN2__A, 3); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN3__A, 3); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN4__A, 3); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN5__A, 0); + if (status < 0) + goto error; + + status = write16(state, QAM_SY_SYNC_HWM__A, 6); + if (status < 0) + goto error; + status = write16(state, QAM_SY_SYNC_AWM__A, 5); + if (status < 0) + goto error; + status = write16(state, QAM_SY_SYNC_LWM__A, 3); + if (status < 0) + goto error; + + /* QAM Slicer Settings */ + + status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM32); + if (status < 0) + goto error; + + + /* QAM Loop Controller Coeficients */ + + status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16); + if (status < 0) + goto error; + + status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 20); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 80); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 20); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 50); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 16); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 16); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 0); + if (status < 0) + goto error; + + + /* QAM State Machine (FSM) Thresholds */ + + status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 90); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 50); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 100); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 170); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 100); + if (status < 0) + goto error; + + status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 10); + if (status < 0) + goto error; + + + /* QAM FSM Tracking Parameters */ + + status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 12); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 140); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) -8); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) -16); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -26); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -56); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -86); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +/*============================================================================*/ + +/** +* \brief QAM64 specific setup +* \param demod instance of demod. +* \return DRXStatus_t. +*/ +static int SetQAM64(struct drxk_state *state) +{ + int status = 0; + + dprintk(1, "\n"); + /* QAM Equalizer Setup */ + /* Equalizer */ + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 13336); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 12618); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 11988); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 13809); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 13809); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 15609); + if (status < 0) + goto error; + + /* Decision Feedback Equalizer */ + status = write16(state, QAM_DQ_QUAL_FUN0__A, 4); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN1__A, 4); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN2__A, 4); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN3__A, 4); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN4__A, 3); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN5__A, 0); + if (status < 0) + goto error; + + status = write16(state, QAM_SY_SYNC_HWM__A, 5); + if (status < 0) + goto error; + status = write16(state, QAM_SY_SYNC_AWM__A, 4); + if (status < 0) + goto error; + status = write16(state, QAM_SY_SYNC_LWM__A, 3); + if (status < 0) + goto error; + + /* QAM Slicer Settings */ + status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM64); + if (status < 0) + goto error; + + + /* QAM Loop Controller Coeficients */ + + status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16); + if (status < 0) + goto error; + + status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 30); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 100); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 30); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 50); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 25); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 48); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 10); + if (status < 0) + goto error; + + + /* QAM State Machine (FSM) Thresholds */ + + status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 100); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 60); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 110); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 200); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 95); + if (status < 0) + goto error; + + status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 15); + if (status < 0) + goto error; + + + /* QAM FSM Tracking Parameters */ + + status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 12); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 141); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 7); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 0); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -15); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -45); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -80); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + + return status; +} + +/*============================================================================*/ + +/** +* \brief QAM128 specific setup +* \param demod: instance of demod. +* \return DRXStatus_t. +*/ +static int SetQAM128(struct drxk_state *state) +{ + int status = 0; + + dprintk(1, "\n"); + /* QAM Equalizer Setup */ + /* Equalizer */ + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 6564); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 6598); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 6394); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 6409); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 6656); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 7238); + if (status < 0) + goto error; + + /* Decision Feedback Equalizer */ + status = write16(state, QAM_DQ_QUAL_FUN0__A, 6); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN1__A, 6); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN2__A, 6); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN3__A, 6); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN4__A, 5); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN5__A, 0); + if (status < 0) + goto error; + + status = write16(state, QAM_SY_SYNC_HWM__A, 6); + if (status < 0) + goto error; + status = write16(state, QAM_SY_SYNC_AWM__A, 5); + if (status < 0) + goto error; + status = write16(state, QAM_SY_SYNC_LWM__A, 3); + if (status < 0) + goto error; + + + /* QAM Slicer Settings */ + + status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM128); + if (status < 0) + goto error; + + + /* QAM Loop Controller Coeficients */ + + status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16); + if (status < 0) + goto error; + + status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 40); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 120); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 40); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 60); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 25); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 64); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 0); + if (status < 0) + goto error; + + + /* QAM State Machine (FSM) Thresholds */ + + status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 50); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 60); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 100); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 140); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 100); + if (status < 0) + goto error; + + status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 5); + if (status < 0) + goto error; + + status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 12); + if (status < 0) + goto error; + + /* QAM FSM Tracking Parameters */ + + status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 8); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 65); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 5); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 3); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -1); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -12); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -23); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + + return status; +} + +/*============================================================================*/ + +/** +* \brief QAM256 specific setup +* \param demod: instance of demod. +* \return DRXStatus_t. +*/ +static int SetQAM256(struct drxk_state *state) +{ + int status = 0; + + dprintk(1, "\n"); + /* QAM Equalizer Setup */ + /* Equalizer */ + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 11502); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 12084); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 12543); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 12931); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 13629); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 15385); + if (status < 0) + goto error; + + /* Decision Feedback Equalizer */ + status = write16(state, QAM_DQ_QUAL_FUN0__A, 8); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN1__A, 8); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN2__A, 8); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN3__A, 8); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN4__A, 6); + if (status < 0) + goto error; + status = write16(state, QAM_DQ_QUAL_FUN5__A, 0); + if (status < 0) + goto error; + + status = write16(state, QAM_SY_SYNC_HWM__A, 5); + if (status < 0) + goto error; + status = write16(state, QAM_SY_SYNC_AWM__A, 4); + if (status < 0) + goto error; + status = write16(state, QAM_SY_SYNC_LWM__A, 3); + if (status < 0) + goto error; + + /* QAM Slicer Settings */ + + status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM256); + if (status < 0) + goto error; + + + /* QAM Loop Controller Coeficients */ + + status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16); + if (status < 0) + goto error; + + status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 50); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 250); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 50); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 125); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 25); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 48); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 10); + if (status < 0) + goto error; + + + /* QAM State Machine (FSM) Thresholds */ + + status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 50); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 60); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 100); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 150); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 110); + if (status < 0) + goto error; + + status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 12); + if (status < 0) + goto error; + + + /* QAM FSM Tracking Parameters */ + + status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 8); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 74); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 18); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 13); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) 7); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) 0); + if (status < 0) + goto error; + status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -8); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + + +/*============================================================================*/ +/** +* \brief Reset QAM block. +* \param demod: instance of demod. +* \param channel: pointer to channel data. +* \return DRXStatus_t. +*/ +static int QAMResetQAM(struct drxk_state *state) +{ + int status; + u16 cmdResult; + + dprintk(1, "\n"); + /* Stop QAM comstate->m_exec */ + status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_STOP); + if (status < 0) + goto error; + + status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +/*============================================================================*/ + +/** +* \brief Set QAM symbolrate. +* \param demod: instance of demod. +* \param channel: pointer to channel data. +* \return DRXStatus_t. +*/ +static int QAMSetSymbolrate(struct drxk_state *state) +{ + u32 adcFrequency = 0; + u32 symbFreq = 0; + u32 iqmRcRate = 0; + u16 ratesel = 0; + u32 lcSymbRate = 0; + int status; + + dprintk(1, "\n"); + /* Select & calculate correct IQM rate */ + adcFrequency = (state->m_sysClockFreq * 1000) / 3; + ratesel = 0; + /* printk(KERN_DEBUG "drxk: SR %d\n", state->param.u.qam.symbol_rate); */ + if (state->param.u.qam.symbol_rate <= 1188750) + ratesel = 3; + else if (state->param.u.qam.symbol_rate <= 2377500) + ratesel = 2; + else if (state->param.u.qam.symbol_rate <= 4755000) + ratesel = 1; + status = write16(state, IQM_FD_RATESEL__A, ratesel); + if (status < 0) + goto error; + + /* + IqmRcRate = ((Fadc / (symbolrate * (4<param.u.qam.symbol_rate * (1 << ratesel); + if (symbFreq == 0) { + /* Divide by zero */ + status = -EINVAL; + goto error; + } + iqmRcRate = (adcFrequency / symbFreq) * (1 << 21) + + (Frac28a((adcFrequency % symbFreq), symbFreq) >> 7) - + (1 << 23); + status = write32(state, IQM_RC_RATE_OFS_LO__A, iqmRcRate); + if (status < 0) + goto error; + state->m_iqmRcRate = iqmRcRate; + /* + LcSymbFreq = round (.125 * symbolrate / adcFreq * (1<<15)) + */ + symbFreq = state->param.u.qam.symbol_rate; + if (adcFrequency == 0) { + /* Divide by zero */ + status = -EINVAL; + goto error; + } + lcSymbRate = (symbFreq / adcFrequency) * (1 << 12) + + (Frac28a((symbFreq % adcFrequency), adcFrequency) >> + 16); + if (lcSymbRate > 511) + lcSymbRate = 511; + status = write16(state, QAM_LC_SYMBOL_FREQ__A, (u16) lcSymbRate); + +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +/*============================================================================*/ + +/** +* \brief Get QAM lock status. +* \param demod: instance of demod. +* \param channel: pointer to channel data. +* \return DRXStatus_t. +*/ + +static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus) +{ + int status; + u16 Result[2] = { 0, 0 }; + + dprintk(1, "\n"); + *pLockStatus = NOT_LOCKED; + status = scu_command(state, + SCU_RAM_COMMAND_STANDARD_QAM | + SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK, 0, NULL, 2, + Result); + if (status < 0) + printk(KERN_ERR "drxk: %s status = %08x\n", __func__, status); + + if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED) { + /* 0x0000 NOT LOCKED */ + } else if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_LOCKED) { + /* 0x4000 DEMOD LOCKED */ + *pLockStatus = DEMOD_LOCK; + } else if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_NEVER_LOCK) { + /* 0x8000 DEMOD + FEC LOCKED (system lock) */ + *pLockStatus = MPEG_LOCK; + } else { + /* 0xC000 NEVER LOCKED */ + /* (system will never be able to lock to the signal) */ + /* TODO: check this, intermediate & standard specific lock states are not + taken into account here */ + *pLockStatus = NEVER_LOCK; + } + return status; +} + +#define QAM_MIRROR__M 0x03 +#define QAM_MIRROR_NORMAL 0x00 +#define QAM_MIRRORED 0x01 +#define QAM_MIRROR_AUTO_ON 0x02 +#define QAM_LOCKRANGE__M 0x10 +#define QAM_LOCKRANGE_NORMAL 0x10 + +static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, + s32 tunerFreqOffset) +{ + int status; + u16 setParamParameters[4] = { 0, 0, 0, 0 }; + u16 cmdResult; + + dprintk(1, "\n"); + /* + * STEP 1: reset demodulator + * resets FEC DI and FEC RS + * resets QAM block + * resets SCU variables + */ + status = write16(state, FEC_DI_COMM_EXEC__A, FEC_DI_COMM_EXEC_STOP); + if (status < 0) + goto error; + status = write16(state, FEC_RS_COMM_EXEC__A, FEC_RS_COMM_EXEC_STOP); + if (status < 0) + goto error; + status = QAMResetQAM(state); + if (status < 0) + goto error; + + /* + * STEP 2: configure demodulator + * -set params; resets IQM,QAM,FEC HW; initializes some + * SCU variables + */ + status = QAMSetSymbolrate(state); + if (status < 0) + goto error; + + /* Set params */ + switch (state->param.u.qam.modulation) { + case QAM_256: + state->m_Constellation = DRX_CONSTELLATION_QAM256; + break; + case QAM_AUTO: + case QAM_64: + state->m_Constellation = DRX_CONSTELLATION_QAM64; + break; + case QAM_16: + state->m_Constellation = DRX_CONSTELLATION_QAM16; + break; + case QAM_32: + state->m_Constellation = DRX_CONSTELLATION_QAM32; + break; + case QAM_128: + state->m_Constellation = DRX_CONSTELLATION_QAM128; + break; + default: + status = -EINVAL; + break; + } + if (status < 0) + goto error; + setParamParameters[0] = state->m_Constellation; /* constellation */ + setParamParameters[1] = DRXK_QAM_I12_J17; /* interleave mode */ + if (state->m_OperationMode == OM_QAM_ITU_C) + setParamParameters[2] = QAM_TOP_ANNEX_C; + else + setParamParameters[2] = QAM_TOP_ANNEX_A; + setParamParameters[3] |= (QAM_MIRROR_AUTO_ON); + /* Env parameters */ + /* check for LOCKRANGE Extented */ + /* setParamParameters[3] |= QAM_LOCKRANGE_NORMAL; */ + + status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, 4, setParamParameters, 1, &cmdResult); + if (status < 0) { + /* Fall-back to the simpler call */ + if (state->m_OperationMode == OM_QAM_ITU_C) + setParamParameters[0] = QAM_TOP_ANNEX_C; + else + setParamParameters[0] = QAM_TOP_ANNEX_A; + status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV, 1, setParamParameters, 1, &cmdResult); + if (status < 0) + goto error; + + setParamParameters[0] = state->m_Constellation; /* constellation */ + setParamParameters[1] = DRXK_QAM_I12_J17; /* interleave mode */ + status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, 2, setParamParameters, 1, &cmdResult); + } + if (status < 0) + goto error; + + /* + * STEP 3: enable the system in a mode where the ADC provides valid + * signal setup constellation independent registers + */ +#if 0 + status = SetFrequency(channel, tunerFreqOffset)); + if (status < 0) + goto error; +#endif + status = SetFrequencyShifter(state, IntermediateFreqkHz, tunerFreqOffset, true); + if (status < 0) + goto error; + + /* Setup BER measurement */ + status = SetQAMMeasurement(state, state->m_Constellation, state->param.u. qam.symbol_rate); + if (status < 0) + goto error; + + /* Reset default values */ + status = write16(state, IQM_CF_SCALE_SH__A, IQM_CF_SCALE_SH__PRE); + if (status < 0) + goto error; + status = write16(state, QAM_SY_TIMEOUT__A, QAM_SY_TIMEOUT__PRE); + if (status < 0) + goto error; + + /* Reset default LC values */ + status = write16(state, QAM_LC_RATE_LIMIT__A, 3); + if (status < 0) + goto error; + status = write16(state, QAM_LC_LPF_FACTORP__A, 4); + if (status < 0) + goto error; + status = write16(state, QAM_LC_LPF_FACTORI__A, 4); + if (status < 0) + goto error; + status = write16(state, QAM_LC_MODE__A, 7); + if (status < 0) + goto error; + + status = write16(state, QAM_LC_QUAL_TAB0__A, 1); + if (status < 0) + goto error; + status = write16(state, QAM_LC_QUAL_TAB1__A, 1); + if (status < 0) + goto error; + status = write16(state, QAM_LC_QUAL_TAB2__A, 1); + if (status < 0) + goto error; + status = write16(state, QAM_LC_QUAL_TAB3__A, 1); + if (status < 0) + goto error; + status = write16(state, QAM_LC_QUAL_TAB4__A, 2); + if (status < 0) + goto error; + status = write16(state, QAM_LC_QUAL_TAB5__A, 2); + if (status < 0) + goto error; + status = write16(state, QAM_LC_QUAL_TAB6__A, 2); + if (status < 0) + goto error; + status = write16(state, QAM_LC_QUAL_TAB8__A, 2); + if (status < 0) + goto error; + status = write16(state, QAM_LC_QUAL_TAB9__A, 2); + if (status < 0) + goto error; + status = write16(state, QAM_LC_QUAL_TAB10__A, 2); + if (status < 0) + goto error; + status = write16(state, QAM_LC_QUAL_TAB12__A, 2); + if (status < 0) + goto error; + status = write16(state, QAM_LC_QUAL_TAB15__A, 3); + if (status < 0) + goto error; + status = write16(state, QAM_LC_QUAL_TAB16__A, 3); + if (status < 0) + goto error; + status = write16(state, QAM_LC_QUAL_TAB20__A, 4); + if (status < 0) + goto error; + status = write16(state, QAM_LC_QUAL_TAB25__A, 4); + if (status < 0) + goto error; + + /* Mirroring, QAM-block starting point not inverted */ + status = write16(state, QAM_SY_SP_INV__A, QAM_SY_SP_INV_SPECTRUM_INV_DIS); + if (status < 0) + goto error; + + /* Halt SCU to enable safe non-atomic accesses */ + status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD); + if (status < 0) + goto error; + + /* STEP 4: constellation specific setup */ + switch (state->param.u.qam.modulation) { + case QAM_16: + status = SetQAM16(state); + break; + case QAM_32: + status = SetQAM32(state); + break; + case QAM_AUTO: + case QAM_64: + status = SetQAM64(state); + break; + case QAM_128: + status = SetQAM128(state); + break; + case QAM_256: + status = SetQAM256(state); + break; + default: + status = -EINVAL; + break; + } + if (status < 0) + goto error; + + /* Activate SCU to enable SCU commands */ + status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE); + if (status < 0) + goto error; + + /* Re-configure MPEG output, requires knowledge of channel bitrate */ + /* extAttr->currentChannel.constellation = channel->constellation; */ + /* extAttr->currentChannel.symbolrate = channel->symbolrate; */ + status = MPEGTSDtoSetup(state, state->m_OperationMode); + if (status < 0) + goto error; + + /* Start processes */ + status = MPEGTSStart(state); + if (status < 0) + goto error; + status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_ACTIVE); + if (status < 0) + goto error; + status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_ACTIVE); + if (status < 0) + goto error; + status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_ACTIVE); + if (status < 0) + goto error; + + /* STEP 5: start QAM demodulator (starts FEC, QAM and IQM HW) */ + status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_START, 0, NULL, 1, &cmdResult); + if (status < 0) + goto error; + + /* update global DRXK data container */ +/*? extAttr->qamInterleaveMode = DRXK_QAM_I12_J17; */ + +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int SetQAMStandard(struct drxk_state *state, + enum OperationMode oMode) +{ + int status; +#ifdef DRXK_QAM_TAPS +#define DRXK_QAMA_TAPS_SELECT +#include "drxk_filters.h" +#undef DRXK_QAMA_TAPS_SELECT +#endif + + dprintk(1, "\n"); + + /* added antenna switch */ + SwitchAntennaToQAM(state); + + /* Ensure correct power-up mode */ + status = PowerUpQAM(state); + if (status < 0) + goto error; + /* Reset QAM block */ + status = QAMResetQAM(state); + if (status < 0) + goto error; + + /* Setup IQM */ + + status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_STOP); + if (status < 0) + goto error; + status = write16(state, IQM_AF_AMUX__A, IQM_AF_AMUX_SIGNAL2ADC); + if (status < 0) + goto error; + + /* Upload IQM Channel Filter settings by + boot loader from ROM table */ + switch (oMode) { + case OM_QAM_ITU_A: + status = BLChainCmd(state, DRXK_BL_ROM_OFFSET_TAPS_ITU_A, DRXK_BLCC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT); + break; + case OM_QAM_ITU_C: + status = BLDirectCmd(state, IQM_CF_TAP_RE0__A, DRXK_BL_ROM_OFFSET_TAPS_ITU_C, DRXK_BLDC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT); + if (status < 0) + goto error; + status = BLDirectCmd(state, IQM_CF_TAP_IM0__A, DRXK_BL_ROM_OFFSET_TAPS_ITU_C, DRXK_BLDC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT); + break; + default: + status = -EINVAL; + } + if (status < 0) + goto error; + + status = write16(state, IQM_CF_OUT_ENA__A, (1 << IQM_CF_OUT_ENA_QAM__B)); + if (status < 0) + goto error; + status = write16(state, IQM_CF_SYMMETRIC__A, 0); + if (status < 0) + goto error; + status = write16(state, IQM_CF_MIDTAP__A, ((1 << IQM_CF_MIDTAP_RE__B) | (1 << IQM_CF_MIDTAP_IM__B))); + if (status < 0) + goto error; + + status = write16(state, IQM_RC_STRETCH__A, 21); + if (status < 0) + goto error; + status = write16(state, IQM_AF_CLP_LEN__A, 0); + if (status < 0) + goto error; + status = write16(state, IQM_AF_CLP_TH__A, 448); + if (status < 0) + goto error; + status = write16(state, IQM_AF_SNS_LEN__A, 0); + if (status < 0) + goto error; + status = write16(state, IQM_CF_POW_MEAS_LEN__A, 0); + if (status < 0) + goto error; + + status = write16(state, IQM_FS_ADJ_SEL__A, 1); + if (status < 0) + goto error; + status = write16(state, IQM_RC_ADJ_SEL__A, 1); + if (status < 0) + goto error; + status = write16(state, IQM_CF_ADJ_SEL__A, 1); + if (status < 0) + goto error; + status = write16(state, IQM_AF_UPD_SEL__A, 0); + if (status < 0) + goto error; + + /* IQM Impulse Noise Processing Unit */ + status = write16(state, IQM_CF_CLP_VAL__A, 500); + if (status < 0) + goto error; + status = write16(state, IQM_CF_DATATH__A, 1000); + if (status < 0) + goto error; + status = write16(state, IQM_CF_BYPASSDET__A, 1); + if (status < 0) + goto error; + status = write16(state, IQM_CF_DET_LCT__A, 0); + if (status < 0) + goto error; + status = write16(state, IQM_CF_WND_LEN__A, 1); + if (status < 0) + goto error; + status = write16(state, IQM_CF_PKDTH__A, 1); + if (status < 0) + goto error; + status = write16(state, IQM_AF_INC_BYPASS__A, 1); + if (status < 0) + goto error; + + /* turn on IQMAF. Must be done before setAgc**() */ + status = SetIqmAf(state, true); + if (status < 0) + goto error; + status = write16(state, IQM_AF_START_LOCK__A, 0x01); + if (status < 0) + goto error; + + /* IQM will not be reset from here, sync ADC and update/init AGC */ + status = ADCSynchronization(state); + if (status < 0) + goto error; + + /* Set the FSM step period */ + status = write16(state, SCU_RAM_QAM_FSM_STEP_PERIOD__A, 2000); + if (status < 0) + goto error; + + /* Halt SCU to enable safe non-atomic accesses */ + status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD); + if (status < 0) + goto error; + + /* No more resets of the IQM, current standard correctly set => + now AGCs can be configured. */ + + status = InitAGC(state, true); + if (status < 0) + goto error; + status = SetPreSaw(state, &(state->m_qamPreSawCfg)); + if (status < 0) + goto error; + + /* Configure AGC's */ + status = SetAgcRf(state, &(state->m_qamRfAgcCfg), true); + if (status < 0) + goto error; + status = SetAgcIf(state, &(state->m_qamIfAgcCfg), true); + if (status < 0) + goto error; + + /* Activate SCU to enable SCU commands */ + status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int WriteGPIO(struct drxk_state *state) +{ + int status; + u16 value = 0; + + dprintk(1, "\n"); + /* stop lock indicator process */ + status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE); + if (status < 0) + goto error; + + /* Write magic word to enable pdr reg write */ + status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY); + if (status < 0) + goto error; + + if (state->m_hasSAWSW) { + if (state->UIO_mask & 0x0001) { /* UIO-1 */ + /* write to io pad configuration register - output mode */ + status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg); + if (status < 0) + goto error; + + /* use corresponding bit in io data output registar */ + status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value); + if (status < 0) + goto error; + if ((state->m_GPIO & 0x0001) == 0) + value &= 0x7FFF; /* write zero to 15th bit - 1st UIO */ + else + value |= 0x8000; /* write one to 15th bit - 1st UIO */ + /* write back to io data output register */ + status = write16(state, SIO_PDR_UIO_OUT_LO__A, value); + if (status < 0) + goto error; + } + if (state->UIO_mask & 0x0002) { /* UIO-2 */ + /* write to io pad configuration register - output mode */ + status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg); + if (status < 0) + goto error; + + /* use corresponding bit in io data output registar */ + status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value); + if (status < 0) + goto error; + if ((state->m_GPIO & 0x0002) == 0) + value &= 0xBFFF; /* write zero to 14th bit - 2st UIO */ + else + value |= 0x4000; /* write one to 14th bit - 2st UIO */ + /* write back to io data output register */ + status = write16(state, SIO_PDR_UIO_OUT_LO__A, value); + if (status < 0) + goto error; + } + if (state->UIO_mask & 0x0004) { /* UIO-3 */ + /* write to io pad configuration register - output mode */ + status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg); + if (status < 0) + goto error; + + /* use corresponding bit in io data output registar */ + status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value); + if (status < 0) + goto error; + if ((state->m_GPIO & 0x0004) == 0) + value &= 0xFFFB; /* write zero to 2nd bit - 3rd UIO */ + else + value |= 0x0004; /* write one to 2nd bit - 3rd UIO */ + /* write back to io data output register */ + status = write16(state, SIO_PDR_UIO_OUT_LO__A, value); + if (status < 0) + goto error; + } + } + /* Write magic word to disable pdr reg write */ + status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int SwitchAntennaToQAM(struct drxk_state *state) +{ + int status = 0; + bool gpio_state; + + dprintk(1, "\n"); + + if (!state->antenna_gpio) + return 0; + + gpio_state = state->m_GPIO & state->antenna_gpio; + + if (state->antenna_dvbt ^ gpio_state) { + /* Antenna is on DVB-T mode. Switch */ + if (state->antenna_dvbt) + state->m_GPIO &= ~state->antenna_gpio; + else + state->m_GPIO |= state->antenna_gpio; + status = WriteGPIO(state); + } + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + +static int SwitchAntennaToDVBT(struct drxk_state *state) +{ + int status = 0; + bool gpio_state; + + dprintk(1, "\n"); + + if (!state->antenna_gpio) + return 0; + + gpio_state = state->m_GPIO & state->antenna_gpio; + + if (!(state->antenna_dvbt ^ gpio_state)) { + /* Antenna is on DVB-C mode. Switch */ + if (state->antenna_dvbt) + state->m_GPIO |= state->antenna_gpio; + else + state->m_GPIO &= ~state->antenna_gpio; + status = WriteGPIO(state); + } + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; +} + + +static int PowerDownDevice(struct drxk_state *state) +{ + /* Power down to requested mode */ + /* Backup some register settings */ + /* Set pins with possible pull-ups connected to them in input mode */ + /* Analog power down */ + /* ADC power down */ + /* Power down device */ + int status; + + dprintk(1, "\n"); + if (state->m_bPDownOpenBridge) { + /* Open I2C bridge before power down of DRXK */ + status = ConfigureI2CBridge(state, true); + if (status < 0) + goto error; + } + /* driver 0.9.0 */ + status = DVBTEnableOFDMTokenRing(state, false); + if (status < 0) + goto error; + + status = write16(state, SIO_CC_PWD_MODE__A, SIO_CC_PWD_MODE_LEVEL_CLOCK); + if (status < 0) + goto error; + status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY); + if (status < 0) + goto error; + state->m_HICfgCtrl |= SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ; + status = HI_CfgCommand(state); +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + + return status; +} + +static int load_microcode(struct drxk_state *state, const char *mc_name) +{ + const struct firmware *fw = NULL; + int err = 0; + + dprintk(1, "\n"); + + err = request_firmware(&fw, mc_name, state->i2c->dev.parent); + if (err < 0) { + printk(KERN_ERR + "drxk: Could not load firmware file %s.\n", mc_name); + printk(KERN_INFO + "drxk: Copy %s to your hotplug directory!\n", mc_name); + return err; + } + err = DownloadMicrocode(state, fw->data, fw->size); + release_firmware(fw); + return err; +} + +static int init_drxk(struct drxk_state *state) +{ + int status = 0; + enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM; + u16 driverVersion; + + dprintk(1, "\n"); + if ((state->m_DrxkState == DRXK_UNINITIALIZED)) { + status = PowerUpDevice(state); + if (status < 0) + goto error; + status = DRXX_Open(state); + if (status < 0) + goto error; + /* Soft reset of OFDM-, sys- and osc-clockdomain */ + status = write16(state, SIO_CC_SOFT_RST__A, SIO_CC_SOFT_RST_OFDM__M | SIO_CC_SOFT_RST_SYS__M | SIO_CC_SOFT_RST_OSC__M); + if (status < 0) + goto error; + status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY); + if (status < 0) + goto error; + /* TODO is this needed, if yes how much delay in worst case scenario */ + msleep(1); + state->m_DRXK_A3_PATCH_CODE = true; + status = GetDeviceCapabilities(state); + if (status < 0) + goto error; + + /* Bridge delay, uses oscilator clock */ + /* Delay = (delay (nano seconds) * oscclk (kHz))/ 1000 */ + /* SDA brdige delay */ + state->m_HICfgBridgeDelay = + (u16) ((state->m_oscClockFreq / 1000) * + HI_I2C_BRIDGE_DELAY) / 1000; + /* Clipping */ + if (state->m_HICfgBridgeDelay > + SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M) { + state->m_HICfgBridgeDelay = + SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M; + } + /* SCL bridge delay, same as SDA for now */ + state->m_HICfgBridgeDelay += + state->m_HICfgBridgeDelay << + SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__B; + + status = InitHI(state); + if (status < 0) + goto error; + /* disable various processes */ +#if NOA1ROM + if (!(state->m_DRXK_A1_ROM_CODE) + && !(state->m_DRXK_A2_ROM_CODE)) +#endif + { + status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE); + if (status < 0) + goto error; + } + + /* disable MPEG port */ + status = MPEGTSDisable(state); + if (status < 0) + goto error; + + /* Stop AUD and SCU */ + status = write16(state, AUD_COMM_EXEC__A, AUD_COMM_EXEC_STOP); + if (status < 0) + goto error; + status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_STOP); + if (status < 0) + goto error; + + /* enable token-ring bus through OFDM block for possible ucode upload */ + status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_ON); + if (status < 0) + goto error; + + /* include boot loader section */ + status = write16(state, SIO_BL_COMM_EXEC__A, SIO_BL_COMM_EXEC_ACTIVE); + if (status < 0) + goto error; + status = BLChainCmd(state, 0, 6, 100); + if (status < 0) + goto error; + + if (!state->microcode_name) + load_microcode(state, "drxk_a3.mc"); + else + load_microcode(state, state->microcode_name); + + /* disable token-ring bus through OFDM block for possible ucode upload */ + status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_OFF); + if (status < 0) + goto error; + + /* Run SCU for a little while to initialize microcode version numbers */ + status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE); + if (status < 0) + goto error; + status = DRXX_Open(state); + if (status < 0) + goto error; + /* added for test */ + msleep(30); + + powerMode = DRXK_POWER_DOWN_OFDM; + status = CtrlPowerMode(state, &powerMode); + if (status < 0) + goto error; + + /* Stamp driver version number in SCU data RAM in BCD code + Done to enable field application engineers to retreive drxdriver version + via I2C from SCU RAM. + Not using SCU command interface for SCU register access since no + microcode may be present. + */ + driverVersion = + (((DRXK_VERSION_MAJOR / 100) % 10) << 12) + + (((DRXK_VERSION_MAJOR / 10) % 10) << 8) + + ((DRXK_VERSION_MAJOR % 10) << 4) + + (DRXK_VERSION_MINOR % 10); + status = write16(state, SCU_RAM_DRIVER_VER_HI__A, driverVersion); + if (status < 0) + goto error; + driverVersion = + (((DRXK_VERSION_PATCH / 1000) % 10) << 12) + + (((DRXK_VERSION_PATCH / 100) % 10) << 8) + + (((DRXK_VERSION_PATCH / 10) % 10) << 4) + + (DRXK_VERSION_PATCH % 10); + status = write16(state, SCU_RAM_DRIVER_VER_LO__A, driverVersion); + if (status < 0) + goto error; + + printk(KERN_INFO "DRXK driver version %d.%d.%d\n", + DRXK_VERSION_MAJOR, DRXK_VERSION_MINOR, + DRXK_VERSION_PATCH); + + /* Dirty fix of default values for ROM/PATCH microcode + Dirty because this fix makes it impossible to setup suitable values + before calling DRX_Open. This solution requires changes to RF AGC speed + to be done via the CTRL function after calling DRX_Open */ + + /* m_dvbtRfAgcCfg.speed = 3; */ + + /* Reset driver debug flags to 0 */ + status = write16(state, SCU_RAM_DRIVER_DEBUG__A, 0); + if (status < 0) + goto error; + /* driver 0.9.0 */ + /* Setup FEC OC: + NOTE: No more full FEC resets allowed afterwards!! */ + status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_STOP); + if (status < 0) + goto error; + /* MPEGTS functions are still the same */ + status = MPEGTSDtoInit(state); + if (status < 0) + goto error; + status = MPEGTSStop(state); + if (status < 0) + goto error; + status = MPEGTSConfigurePolarity(state); + if (status < 0) + goto error; + status = MPEGTSConfigurePins(state, state->m_enableMPEGOutput); + if (status < 0) + goto error; + /* added: configure GPIO */ + status = WriteGPIO(state); + if (status < 0) + goto error; + + state->m_DrxkState = DRXK_STOPPED; + + if (state->m_bPowerDown) { + status = PowerDownDevice(state); + if (status < 0) + goto error; + state->m_DrxkState = DRXK_POWERED_DOWN; + } else + state->m_DrxkState = DRXK_STOPPED; + } +error: + if (status < 0) + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + + return status; +} + +static void drxk_c_release(struct dvb_frontend *fe) +{ + struct drxk_state *state = fe->demodulator_priv; + + dprintk(1, "\n"); + kfree(state); +} + +static int drxk_c_init(struct dvb_frontend *fe) +{ + struct drxk_state *state = fe->demodulator_priv; + + dprintk(1, "\n"); + if (mutex_trylock(&state->ctlock) == 0) + return -EBUSY; + SetOperationMode(state, OM_QAM_ITU_A); + return 0; +} + +static int drxk_c_sleep(struct dvb_frontend *fe) +{ + struct drxk_state *state = fe->demodulator_priv; + + dprintk(1, "\n"); + ShutDown(state); + mutex_unlock(&state->ctlock); + return 0; +} + +static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct drxk_state *state = fe->demodulator_priv; + + dprintk(1, "%s\n", enable ? "enable" : "disable"); + return ConfigureI2CBridge(state, enable ? true : false); +} + +static int drxk_set_parameters(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct drxk_state *state = fe->demodulator_priv; + u32 IF; + + dprintk(1, "\n"); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + state->param = *p; + fe->ops.tuner_ops.get_frequency(fe, &IF); + Start(state, 0, IF); + + /* printk(KERN_DEBUG "drxk: %s IF=%d done\n", __func__, IF); */ + + return 0; +} + +static int drxk_c_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + dprintk(1, "\n"); + return 0; +} + +static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct drxk_state *state = fe->demodulator_priv; + u32 stat; + + dprintk(1, "\n"); + *status = 0; + GetLockStatus(state, &stat, 0); + if (stat == MPEG_LOCK) + *status |= 0x1f; + if (stat == FEC_LOCK) + *status |= 0x0f; + if (stat == DEMOD_LOCK) + *status |= 0x07; + return 0; +} + +static int drxk_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + dprintk(1, "\n"); + + *ber = 0; + return 0; +} + +static int drxk_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + struct drxk_state *state = fe->demodulator_priv; + u32 val = 0; + + dprintk(1, "\n"); + ReadIFAgc(state, &val); + *strength = val & 0xffff; + return 0; +} + +static int drxk_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct drxk_state *state = fe->demodulator_priv; + s32 snr2; + + dprintk(1, "\n"); + GetSignalToNoise(state, &snr2); + *snr = snr2 & 0xffff; + return 0; +} + +static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct drxk_state *state = fe->demodulator_priv; + u16 err; + + dprintk(1, "\n"); + DVBTQAMGetAccPktErr(state, &err); + *ucblocks = (u32) err; + return 0; +} + +static int drxk_c_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings + *sets) +{ + dprintk(1, "\n"); + sets->min_delay_ms = 3000; + sets->max_drift = 0; + sets->step_size = 0; + return 0; +} + +static void drxk_t_release(struct dvb_frontend *fe) +{ + /* + * There's nothing to release here, as the state struct + * is already freed by drxk_c_release. + */ +} + +static int drxk_t_init(struct dvb_frontend *fe) +{ + struct drxk_state *state = fe->demodulator_priv; + + dprintk(1, "\n"); + if (mutex_trylock(&state->ctlock) == 0) + return -EBUSY; + SetOperationMode(state, OM_DVBT); + return 0; +} + +static int drxk_t_sleep(struct dvb_frontend *fe) +{ + struct drxk_state *state = fe->demodulator_priv; + + dprintk(1, "\n"); + mutex_unlock(&state->ctlock); + return 0; +} + +static int drxk_t_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + dprintk(1, "\n"); + + return 0; +} + +static struct dvb_frontend_ops drxk_c_ops = { + .info = { + .name = "DRXK DVB-C", + .type = FE_QAM, + .frequency_stepsize = 62500, + .frequency_min = 47000000, + .frequency_max = 862000000, + .symbol_rate_min = 870000, + .symbol_rate_max = 11700000, + .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | + FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO}, + .release = drxk_c_release, + .init = drxk_c_init, + .sleep = drxk_c_sleep, + .i2c_gate_ctrl = drxk_gate_ctrl, + + .set_frontend = drxk_set_parameters, + .get_frontend = drxk_c_get_frontend, + .get_tune_settings = drxk_c_get_tune_settings, + + .read_status = drxk_read_status, + .read_ber = drxk_read_ber, + .read_signal_strength = drxk_read_signal_strength, + .read_snr = drxk_read_snr, + .read_ucblocks = drxk_read_ucblocks, +}; + +static struct dvb_frontend_ops drxk_t_ops = { + .info = { + .name = "DRXK DVB-T", + .type = FE_OFDM, + .frequency_min = 47125000, + .frequency_max = 865000000, + .frequency_stepsize = 166667, + .frequency_tolerance = 0, + .caps = 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_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS}, + .release = drxk_t_release, + .init = drxk_t_init, + .sleep = drxk_t_sleep, + .i2c_gate_ctrl = drxk_gate_ctrl, + + .set_frontend = drxk_set_parameters, + .get_frontend = drxk_t_get_frontend, + + .read_status = drxk_read_status, + .read_ber = drxk_read_ber, + .read_signal_strength = drxk_read_signal_strength, + .read_snr = drxk_read_snr, + .read_ucblocks = drxk_read_ucblocks, +}; + +struct dvb_frontend *drxk_attach(const struct drxk_config *config, + struct i2c_adapter *i2c, + struct dvb_frontend **fe_t) +{ + struct drxk_state *state = NULL; + u8 adr = config->adr; + + dprintk(1, "\n"); + state = kzalloc(sizeof(struct drxk_state), GFP_KERNEL); + if (!state) + return NULL; + + state->i2c = i2c; + state->demod_address = adr; + state->single_master = config->single_master; + state->microcode_name = config->microcode_name; + state->no_i2c_bridge = config->no_i2c_bridge; + state->antenna_gpio = config->antenna_gpio; + state->antenna_dvbt = config->antenna_dvbt; + + /* NOTE: as more UIO bits will be used, add them to the mask */ + state->UIO_mask = config->antenna_gpio; + + /* Default gpio to DVB-C */ + if (!state->antenna_dvbt && state->antenna_gpio) + state->m_GPIO |= state->antenna_gpio; + else + state->m_GPIO &= ~state->antenna_gpio; + + mutex_init(&state->mutex); + mutex_init(&state->ctlock); + + memcpy(&state->c_frontend.ops, &drxk_c_ops, + sizeof(struct dvb_frontend_ops)); + memcpy(&state->t_frontend.ops, &drxk_t_ops, + sizeof(struct dvb_frontend_ops)); + state->c_frontend.demodulator_priv = state; + state->t_frontend.demodulator_priv = state; + + init_state(state); + if (init_drxk(state) < 0) + goto error; + *fe_t = &state->t_frontend; + + return &state->c_frontend; + +error: + printk(KERN_ERR "drxk: not found\n"); + kfree(state); + return NULL; +} +EXPORT_SYMBOL(drxk_attach); + +MODULE_DESCRIPTION("DRX-K driver"); +MODULE_AUTHOR("Ralph Metzler"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/drxk_hard.h b/drivers/media/dvb/frontends/drxk_hard.h new file mode 100644 index 0000000000000000000000000000000000000000..a05c32eecdcc7de893a297c6faf53b54324a040c --- /dev/null +++ b/drivers/media/dvb/frontends/drxk_hard.h @@ -0,0 +1,348 @@ +#include "drxk_map.h" + +#define DRXK_VERSION_MAJOR 0 +#define DRXK_VERSION_MINOR 9 +#define DRXK_VERSION_PATCH 4300 + +#define HI_I2C_DELAY 42 +#define HI_I2C_BRIDGE_DELAY 350 +#define DRXK_MAX_RETRIES 100 + +#define DRIVER_4400 1 + +#define DRXX_JTAGID 0x039210D9 +#define DRXX_J_JTAGID 0x239310D9 +#define DRXX_K_JTAGID 0x039210D9 + +#define DRX_UNKNOWN 254 +#define DRX_AUTO 255 + +#define DRX_SCU_READY 0 +#define DRXK_MAX_WAITTIME (200) +#define SCU_RESULT_OK 0 +#define SCU_RESULT_SIZE -4 +#define SCU_RESULT_INVPAR -3 +#define SCU_RESULT_UNKSTD -2 +#define SCU_RESULT_UNKCMD -1 + +#ifndef DRXK_OFDM_TR_SHUTDOWN_TIMEOUT +#define DRXK_OFDM_TR_SHUTDOWN_TIMEOUT (200) +#endif + +#define DRXK_8VSB_MPEG_BIT_RATE 19392658UL /*bps*/ +#define DRXK_DVBT_MPEG_BIT_RATE 32000000UL /*bps*/ +#define DRXK_QAM16_MPEG_BIT_RATE 27000000UL /*bps*/ +#define DRXK_QAM32_MPEG_BIT_RATE 33000000UL /*bps*/ +#define DRXK_QAM64_MPEG_BIT_RATE 40000000UL /*bps*/ +#define DRXK_QAM128_MPEG_BIT_RATE 46000000UL /*bps*/ +#define DRXK_QAM256_MPEG_BIT_RATE 52000000UL /*bps*/ +#define DRXK_MAX_MPEG_BIT_RATE 52000000UL /*bps*/ + +#define IQM_CF_OUT_ENA_OFDM__M 0x4 +#define IQM_FS_ADJ_SEL_B_QAM 0x1 +#define IQM_FS_ADJ_SEL_B_OFF 0x0 +#define IQM_FS_ADJ_SEL_B_VSB 0x2 +#define IQM_RC_ADJ_SEL_B_OFF 0x0 +#define IQM_RC_ADJ_SEL_B_QAM 0x1 +#define IQM_RC_ADJ_SEL_B_VSB 0x2 + +enum OperationMode { + OM_NONE, + OM_QAM_ITU_A, + OM_QAM_ITU_B, + OM_QAM_ITU_C, + OM_DVBT +}; + +enum DRXPowerMode { + DRX_POWER_UP = 0, + DRX_POWER_MODE_1, + DRX_POWER_MODE_2, + DRX_POWER_MODE_3, + DRX_POWER_MODE_4, + DRX_POWER_MODE_5, + DRX_POWER_MODE_6, + DRX_POWER_MODE_7, + DRX_POWER_MODE_8, + + DRX_POWER_MODE_9, + DRX_POWER_MODE_10, + DRX_POWER_MODE_11, + DRX_POWER_MODE_12, + DRX_POWER_MODE_13, + DRX_POWER_MODE_14, + DRX_POWER_MODE_15, + DRX_POWER_MODE_16, + DRX_POWER_DOWN = 255 +}; + + +/** /brief Intermediate power mode for DRXK, power down OFDM clock domain */ +#ifndef DRXK_POWER_DOWN_OFDM +#define DRXK_POWER_DOWN_OFDM DRX_POWER_MODE_1 +#endif + +/** /brief Intermediate power mode for DRXK, power down core (sysclk) */ +#ifndef DRXK_POWER_DOWN_CORE +#define DRXK_POWER_DOWN_CORE DRX_POWER_MODE_9 +#endif + +/** /brief Intermediate power mode for DRXK, power down pll (only osc runs) */ +#ifndef DRXK_POWER_DOWN_PLL +#define DRXK_POWER_DOWN_PLL DRX_POWER_MODE_10 +#endif + + +enum AGC_CTRL_MODE { DRXK_AGC_CTRL_AUTO = 0, DRXK_AGC_CTRL_USER, DRXK_AGC_CTRL_OFF }; +enum EDrxkState { DRXK_UNINITIALIZED = 0, DRXK_STOPPED, DRXK_DTV_STARTED, DRXK_ATV_STARTED, DRXK_POWERED_DOWN }; +enum EDrxkCoefArrayIndex { + DRXK_COEF_IDX_MN = 0, + DRXK_COEF_IDX_FM , + DRXK_COEF_IDX_L , + DRXK_COEF_IDX_LP , + DRXK_COEF_IDX_BG , + DRXK_COEF_IDX_DK , + DRXK_COEF_IDX_I , + DRXK_COEF_IDX_MAX +}; +enum EDrxkSifAttenuation { + DRXK_SIF_ATTENUATION_0DB, + DRXK_SIF_ATTENUATION_3DB, + DRXK_SIF_ATTENUATION_6DB, + DRXK_SIF_ATTENUATION_9DB +}; +enum EDrxkConstellation { + DRX_CONSTELLATION_BPSK = 0, + DRX_CONSTELLATION_QPSK, + DRX_CONSTELLATION_PSK8, + DRX_CONSTELLATION_QAM16, + DRX_CONSTELLATION_QAM32, + DRX_CONSTELLATION_QAM64, + DRX_CONSTELLATION_QAM128, + DRX_CONSTELLATION_QAM256, + DRX_CONSTELLATION_QAM512, + DRX_CONSTELLATION_QAM1024, + DRX_CONSTELLATION_UNKNOWN = DRX_UNKNOWN, + DRX_CONSTELLATION_AUTO = DRX_AUTO +}; +enum EDrxkInterleaveMode { + DRXK_QAM_I12_J17 = 16, + DRXK_QAM_I_UNKNOWN = DRX_UNKNOWN +}; +enum { + DRXK_SPIN_A1 = 0, + DRXK_SPIN_A2, + DRXK_SPIN_A3, + DRXK_SPIN_UNKNOWN +}; + +enum DRXKCfgDvbtSqiSpeed { + DRXK_DVBT_SQI_SPEED_FAST = 0, + DRXK_DVBT_SQI_SPEED_MEDIUM, + DRXK_DVBT_SQI_SPEED_SLOW, + DRXK_DVBT_SQI_SPEED_UNKNOWN = DRX_UNKNOWN +} ; + +enum DRXFftmode_t { + DRX_FFTMODE_2K = 0, + DRX_FFTMODE_4K, + DRX_FFTMODE_8K, + DRX_FFTMODE_UNKNOWN = DRX_UNKNOWN, + DRX_FFTMODE_AUTO = DRX_AUTO +}; + +enum DRXMPEGStrWidth_t { + DRX_MPEG_STR_WIDTH_1, + DRX_MPEG_STR_WIDTH_8 +}; + +enum DRXQamLockRange_t { + DRX_QAM_LOCKRANGE_NORMAL, + DRX_QAM_LOCKRANGE_EXTENDED +}; + +struct DRXKCfgDvbtEchoThres_t { + u16 threshold; + enum DRXFftmode_t fftMode; +} ; + +struct SCfgAgc { + enum AGC_CTRL_MODE ctrlMode; /* off, user, auto */ + u16 outputLevel; /* range dependent on AGC */ + u16 minOutputLevel; /* range dependent on AGC */ + u16 maxOutputLevel; /* range dependent on AGC */ + u16 speed; /* range dependent on AGC */ + u16 top; /* rf-agc take over point */ + u16 cutOffCurrent; /* rf-agc is accelerated if output current + is below cut-off current */ + u16 IngainTgtMax; + u16 FastClipCtrlDelay; +}; + +struct SCfgPreSaw { + u16 reference; /* pre SAW reference value, range 0 .. 31 */ + bool usePreSaw; /* TRUE algorithms must use pre SAW sense */ +}; + +struct DRXKOfdmScCmd_t { + u16 cmd; /**< Command number */ + u16 subcmd; /**< Sub-command parameter*/ + u16 param0; /**< General purpous param */ + u16 param1; /**< General purpous param */ + u16 param2; /**< General purpous param */ + u16 param3; /**< General purpous param */ + u16 param4; /**< General purpous param */ +}; + +struct drxk_state { + struct dvb_frontend c_frontend; + struct dvb_frontend t_frontend; + struct dvb_frontend_parameters param; + struct device *dev; + + struct i2c_adapter *i2c; + u8 demod_address; + void *priv; + + struct mutex mutex; + struct mutex ctlock; + + u32 m_Instance; /**< Channel 1,2,3 or 4 */ + + int m_ChunkSize; + u8 Chunk[256]; + + bool m_hasLNA; + bool m_hasDVBT; + bool m_hasDVBC; + bool m_hasAudio; + bool m_hasATV; + bool m_hasOOB; + bool m_hasSAWSW; /**< TRUE if mat_tx is available */ + bool m_hasGPIO1; /**< TRUE if mat_rx is available */ + bool m_hasGPIO2; /**< TRUE if GPIO is available */ + bool m_hasIRQN; /**< TRUE if IRQN is available */ + u16 m_oscClockFreq; + u16 m_HICfgTimingDiv; + u16 m_HICfgBridgeDelay; + u16 m_HICfgWakeUpKey; + u16 m_HICfgTimeout; + u16 m_HICfgCtrl; + s32 m_sysClockFreq; /**< system clock frequency in kHz */ + + enum EDrxkState m_DrxkState; /**< State of Drxk (init,stopped,started) */ + enum OperationMode m_OperationMode; /**< digital standards */ + struct SCfgAgc m_vsbRfAgcCfg; /**< settings for VSB RF-AGC */ + struct SCfgAgc m_vsbIfAgcCfg; /**< settings for VSB IF-AGC */ + u16 m_vsbPgaCfg; /**< settings for VSB PGA */ + struct SCfgPreSaw m_vsbPreSawCfg; /**< settings for pre SAW sense */ + s32 m_Quality83percent; /**< MER level (*0.1 dB) for 83% quality indication */ + s32 m_Quality93percent; /**< MER level (*0.1 dB) for 93% quality indication */ + bool m_smartAntInverted; + bool m_bDebugEnableBridge; + bool m_bPDownOpenBridge; /**< only open DRXK bridge before power-down once it has been accessed */ + bool m_bPowerDown; /**< Power down when not used */ + + u32 m_IqmFsRateOfs; /**< frequency shift as written to DRXK register (28bit fixpoint) */ + + bool m_enableMPEGOutput; /**< If TRUE, enable MPEG output */ + bool m_insertRSByte; /**< If TRUE, insert RS byte */ + bool m_enableParallel; /**< If TRUE, parallel out otherwise serial */ + bool m_invertDATA; /**< If TRUE, invert DATA signals */ + bool m_invertERR; /**< If TRUE, invert ERR signal */ + bool m_invertSTR; /**< If TRUE, invert STR signals */ + bool m_invertVAL; /**< If TRUE, invert VAL signals */ + bool m_invertCLK; /**< If TRUE, invert CLK signals */ + bool m_DVBCStaticCLK; + bool m_DVBTStaticCLK; /**< If TRUE, static MPEG clockrate will + be used, otherwise clockrate will + adapt to the bitrate of the TS */ + u32 m_DVBTBitrate; + u32 m_DVBCBitrate; + + u8 m_TSDataStrength; + u8 m_TSClockkStrength; + + enum DRXMPEGStrWidth_t m_widthSTR; /**< MPEG start width */ + u32 m_mpegTsStaticBitrate; /**< Maximum bitrate in b/s in case + static clockrate is selected */ + + /* LARGE_INTEGER m_StartTime; */ /**< Contains the time of the last demod start */ + s32 m_MpegLockTimeOut; /**< WaitForLockStatus Timeout (counts from start time) */ + s32 m_DemodLockTimeOut; /**< WaitForLockStatus Timeout (counts from start time) */ + + bool m_disableTEIhandling; + + bool m_RfAgcPol; + bool m_IfAgcPol; + + struct SCfgAgc m_atvRfAgcCfg; /**< settings for ATV RF-AGC */ + struct SCfgAgc m_atvIfAgcCfg; /**< settings for ATV IF-AGC */ + struct SCfgPreSaw m_atvPreSawCfg; /**< settings for ATV pre SAW sense */ + bool m_phaseCorrectionBypass; + s16 m_atvTopVidPeak; + u16 m_atvTopNoiseTh; + enum EDrxkSifAttenuation m_sifAttenuation; + bool m_enableCVBSOutput; + bool m_enableSIFOutput; + bool m_bMirrorFreqSpect; + enum EDrxkConstellation m_Constellation; /**< Constellation type of the channel */ + u32 m_CurrSymbolRate; /**< Current QAM symbol rate */ + struct SCfgAgc m_qamRfAgcCfg; /**< settings for QAM RF-AGC */ + struct SCfgAgc m_qamIfAgcCfg; /**< settings for QAM IF-AGC */ + u16 m_qamPgaCfg; /**< settings for QAM PGA */ + struct SCfgPreSaw m_qamPreSawCfg; /**< settings for QAM pre SAW sense */ + enum EDrxkInterleaveMode m_qamInterleaveMode; /**< QAM Interleave mode */ + u16 m_fecRsPlen; + u16 m_fecRsPrescale; + + enum DRXKCfgDvbtSqiSpeed m_sqiSpeed; + + u16 m_GPIO; + u16 m_GPIOCfg; + + struct SCfgAgc m_dvbtRfAgcCfg; /**< settings for QAM RF-AGC */ + struct SCfgAgc m_dvbtIfAgcCfg; /**< settings for QAM IF-AGC */ + struct SCfgPreSaw m_dvbtPreSawCfg; /**< settings for QAM pre SAW sense */ + + u16 m_agcFastClipCtrlDelay; + bool m_adcCompPassed; + u16 m_adcCompCoef[64]; + u16 m_adcState; + + u8 *m_microcode; + int m_microcode_length; + bool m_DRXK_A1_PATCH_CODE; + bool m_DRXK_A1_ROM_CODE; + bool m_DRXK_A2_ROM_CODE; + bool m_DRXK_A3_ROM_CODE; + bool m_DRXK_A2_PATCH_CODE; + bool m_DRXK_A3_PATCH_CODE; + + bool m_rfmirror; + u8 m_deviceSpin; + u32 m_iqmRcRate; + + enum DRXPowerMode m_currentPowerMode; + + /* + * Configurable parameters at the driver. They stores the values found + * at struct drxk_config. + */ + + u16 UIO_mask; /* Bits used by UIO */ + + bool single_master; + bool no_i2c_bridge; + bool antenna_dvbt; + u16 antenna_gpio; + + const char *microcode_name; +}; + +#define NEVER_LOCK 0 +#define NOT_LOCKED 1 +#define DEMOD_LOCK 2 +#define FEC_LOCK 3 +#define MPEG_LOCK 4 + diff --git a/drivers/media/dvb/frontends/drxk_map.h b/drivers/media/dvb/frontends/drxk_map.h new file mode 100644 index 0000000000000000000000000000000000000000..9b11a832886936d9c932b68dd433500cc429fb29 --- /dev/null +++ b/drivers/media/dvb/frontends/drxk_map.h @@ -0,0 +1,449 @@ +#define AUD_COMM_EXEC__A 0x1000000 +#define AUD_COMM_EXEC_STOP 0x0 +#define FEC_COMM_EXEC__A 0x1C00000 +#define FEC_COMM_EXEC_STOP 0x0 +#define FEC_COMM_EXEC_ACTIVE 0x1 +#define FEC_DI_COMM_EXEC__A 0x1C20000 +#define FEC_DI_COMM_EXEC_STOP 0x0 +#define FEC_DI_INPUT_CTL__A 0x1C20016 +#define FEC_RS_COMM_EXEC__A 0x1C30000 +#define FEC_RS_COMM_EXEC_STOP 0x0 +#define FEC_RS_MEASUREMENT_PERIOD__A 0x1C30012 +#define FEC_RS_MEASUREMENT_PRESCALE__A 0x1C30013 +#define FEC_OC_MODE__A 0x1C40011 +#define FEC_OC_MODE_PARITY__M 0x1 +#define FEC_OC_DTO_MODE__A 0x1C40014 +#define FEC_OC_DTO_MODE_DYNAMIC__M 0x1 +#define FEC_OC_DTO_MODE_OFFSET_ENABLE__M 0x4 +#define FEC_OC_DTO_PERIOD__A 0x1C40015 +#define FEC_OC_DTO_BURST_LEN__A 0x1C40018 +#define FEC_OC_FCT_MODE__A 0x1C4001A +#define FEC_OC_FCT_MODE__PRE 0x0 +#define FEC_OC_FCT_MODE_RAT_ENA__M 0x1 +#define FEC_OC_FCT_MODE_VIRT_ENA__M 0x2 +#define FEC_OC_TMD_MODE__A 0x1C4001E +#define FEC_OC_TMD_COUNT__A 0x1C4001F +#define FEC_OC_TMD_HI_MARGIN__A 0x1C40020 +#define FEC_OC_TMD_LO_MARGIN__A 0x1C40021 +#define FEC_OC_TMD_INT_UPD_RATE__A 0x1C40023 +#define FEC_OC_AVR_PARM_A__A 0x1C40026 +#define FEC_OC_AVR_PARM_B__A 0x1C40027 +#define FEC_OC_RCN_GAIN__A 0x1C4002E +#define FEC_OC_RCN_CTL_RATE_LO__A 0x1C40030 +#define FEC_OC_RCN_CTL_STEP_LO__A 0x1C40032 +#define FEC_OC_RCN_CTL_STEP_HI__A 0x1C40033 +#define FEC_OC_SNC_MODE__A 0x1C40040 +#define FEC_OC_SNC_MODE_SHUTDOWN__M 0x10 +#define FEC_OC_SNC_LWM__A 0x1C40041 +#define FEC_OC_SNC_HWM__A 0x1C40042 +#define FEC_OC_SNC_UNLOCK__A 0x1C40043 +#define FEC_OC_SNC_FAIL_PERIOD__A 0x1C40046 +#define FEC_OC_IPR_MODE__A 0x1C40048 +#define FEC_OC_IPR_MODE_SERIAL__M 0x1 +#define FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__M 0x4 +#define FEC_OC_IPR_MODE_MVAL_DIS_PAR__M 0x10 +#define FEC_OC_IPR_INVERT__A 0x1C40049 +#define FEC_OC_IPR_INVERT_MD0__M 0x1 +#define FEC_OC_IPR_INVERT_MD1__M 0x2 +#define FEC_OC_IPR_INVERT_MD2__M 0x4 +#define FEC_OC_IPR_INVERT_MD3__M 0x8 +#define FEC_OC_IPR_INVERT_MD4__M 0x10 +#define FEC_OC_IPR_INVERT_MD5__M 0x20 +#define FEC_OC_IPR_INVERT_MD6__M 0x40 +#define FEC_OC_IPR_INVERT_MD7__M 0x80 +#define FEC_OC_IPR_INVERT_MERR__M 0x100 +#define FEC_OC_IPR_INVERT_MSTRT__M 0x200 +#define FEC_OC_IPR_INVERT_MVAL__M 0x400 +#define FEC_OC_IPR_INVERT_MCLK__M 0x800 +#define FEC_OC_OCR_INVERT__A 0x1C40052 +#define IQM_COMM_EXEC__A 0x1800000 +#define IQM_COMM_EXEC_B_STOP 0x0 +#define IQM_COMM_EXEC_B_ACTIVE 0x1 +#define IQM_FS_RATE_OFS_LO__A 0x1820010 +#define IQM_FS_ADJ_SEL__A 0x1820014 +#define IQM_FS_ADJ_SEL_B_OFF 0x0 +#define IQM_FS_ADJ_SEL_B_QAM 0x1 +#define IQM_FS_ADJ_SEL_B_VSB 0x2 +#define IQM_FD_RATESEL__A 0x1830010 +#define IQM_RC_RATE_OFS_LO__A 0x1840010 +#define IQM_RC_RATE_OFS_LO__W 16 +#define IQM_RC_RATE_OFS_LO__M 0xFFFF +#define IQM_RC_RATE_OFS_HI__M 0xFF +#define IQM_RC_ADJ_SEL__A 0x1840014 +#define IQM_RC_ADJ_SEL_B_OFF 0x0 +#define IQM_RC_ADJ_SEL_B_QAM 0x1 +#define IQM_RC_ADJ_SEL_B_VSB 0x2 +#define IQM_RC_STRETCH__A 0x1840016 +#define IQM_CF_COMM_INT_MSK__A 0x1860006 +#define IQM_CF_SYMMETRIC__A 0x1860010 +#define IQM_CF_MIDTAP__A 0x1860011 +#define IQM_CF_MIDTAP_RE__B 0 +#define IQM_CF_MIDTAP_IM__B 1 +#define IQM_CF_OUT_ENA__A 0x1860012 +#define IQM_CF_OUT_ENA_QAM__B 1 +#define IQM_CF_OUT_ENA_OFDM__M 0x4 +#define IQM_CF_ADJ_SEL__A 0x1860013 +#define IQM_CF_SCALE__A 0x1860014 +#define IQM_CF_SCALE_SH__A 0x1860015 +#define IQM_CF_SCALE_SH__PRE 0x0 +#define IQM_CF_POW_MEAS_LEN__A 0x1860017 +#define IQM_CF_DS_ENA__A 0x1860019 +#define IQM_CF_TAP_RE0__A 0x1860020 +#define IQM_CF_TAP_IM0__A 0x1860040 +#define IQM_CF_CLP_VAL__A 0x1860060 +#define IQM_CF_DATATH__A 0x1860061 +#define IQM_CF_PKDTH__A 0x1860062 +#define IQM_CF_WND_LEN__A 0x1860063 +#define IQM_CF_DET_LCT__A 0x1860064 +#define IQM_CF_BYPASSDET__A 0x1860067 +#define IQM_AF_COMM_EXEC__A 0x1870000 +#define IQM_AF_COMM_EXEC_ACTIVE 0x1 +#define IQM_AF_CLKNEG__A 0x1870012 +#define IQM_AF_CLKNEG_CLKNEGDATA__M 0x2 +#define IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS 0x0 +#define IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_NEG 0x2 +#define IQM_AF_START_LOCK__A 0x187001B +#define IQM_AF_PHASE0__A 0x187001C +#define IQM_AF_PHASE1__A 0x187001D +#define IQM_AF_PHASE2__A 0x187001E +#define IQM_AF_CLP_LEN__A 0x1870023 +#define IQM_AF_CLP_TH__A 0x1870024 +#define IQM_AF_SNS_LEN__A 0x1870026 +#define IQM_AF_AGC_IF__A 0x1870028 +#define IQM_AF_AGC_RF__A 0x1870029 +#define IQM_AF_PDREF__A 0x187002B +#define IQM_AF_PDREF__M 0x1F +#define IQM_AF_STDBY__A 0x187002C +#define IQM_AF_STDBY_STDBY_ADC_STANDBY 0x2 +#define IQM_AF_STDBY_STDBY_AMP_STANDBY 0x4 +#define IQM_AF_STDBY_STDBY_PD_STANDBY 0x8 +#define IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY 0x10 +#define IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY 0x20 +#define IQM_AF_AMUX__A 0x187002D +#define IQM_AF_AMUX_SIGNAL2ADC 0x1 +#define IQM_AF_UPD_SEL__A 0x187002F +#define IQM_AF_INC_LCT__A 0x1870034 +#define IQM_AF_INC_BYPASS__A 0x1870036 +#define OFDM_CP_COMM_EXEC__A 0x2800000 +#define OFDM_CP_COMM_EXEC_STOP 0x0 +#define OFDM_EC_SB_PRIOR__A 0x3410013 +#define OFDM_EC_SB_PRIOR_HI 0x0 +#define OFDM_EC_SB_PRIOR_LO 0x1 +#define OFDM_EQ_TOP_TD_TPS_CONST__A 0x3010054 +#define OFDM_EQ_TOP_TD_TPS_CONST__M 0x3 +#define OFDM_EQ_TOP_TD_TPS_CONST_64QAM 0x2 +#define OFDM_EQ_TOP_TD_TPS_CODE_HP__A 0x3010056 +#define OFDM_EQ_TOP_TD_TPS_CODE_HP__M 0x7 +#define OFDM_EQ_TOP_TD_TPS_CODE_LP_7_8 0x4 +#define OFDM_EQ_TOP_TD_SQR_ERR_I__A 0x301005E +#define OFDM_EQ_TOP_TD_SQR_ERR_Q__A 0x301005F +#define OFDM_EQ_TOP_TD_SQR_ERR_EXP__A 0x3010060 +#define OFDM_EQ_TOP_TD_REQ_SMB_CNT__A 0x3010061 +#define OFDM_EQ_TOP_TD_TPS_PWR_OFS__A 0x3010062 +#define OFDM_LC_COMM_EXEC__A 0x3800000 +#define OFDM_LC_COMM_EXEC_STOP 0x0 +#define OFDM_SC_COMM_EXEC__A 0x3C00000 +#define OFDM_SC_COMM_EXEC_STOP 0x0 +#define OFDM_SC_COMM_STATE__A 0x3C00001 +#define OFDM_SC_RA_RAM_PARAM0__A 0x3C20040 +#define OFDM_SC_RA_RAM_PARAM1__A 0x3C20041 +#define OFDM_SC_RA_RAM_CMD_ADDR__A 0x3C20042 +#define OFDM_SC_RA_RAM_CMD__A 0x3C20043 +#define OFDM_SC_RA_RAM_CMD_NULL 0x0 +#define OFDM_SC_RA_RAM_CMD_PROC_START 0x1 +#define OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM 0x3 +#define OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM 0x4 +#define OFDM_SC_RA_RAM_CMD_GET_OP_PARAM 0x5 +#define OFDM_SC_RA_RAM_CMD_USER_IO 0x6 +#define OFDM_SC_RA_RAM_CMD_SET_TIMER 0x7 +#define OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING 0x8 +#define OFDM_SC_RA_RAM_SW_EVENT_RUN_NMASK__M 0x1 +#define OFDM_SC_RA_RAM_LOCKTRACK_MIN 0x1 +#define OFDM_SC_RA_RAM_OP_PARAM__A 0x3C20048 +#define OFDM_SC_RA_RAM_OP_PARAM_MODE__M 0x3 +#define OFDM_SC_RA_RAM_OP_PARAM_MODE_2K 0x0 +#define OFDM_SC_RA_RAM_OP_PARAM_MODE_8K 0x1 +#define OFDM_SC_RA_RAM_OP_PARAM_GUARD_32 0x0 +#define OFDM_SC_RA_RAM_OP_PARAM_GUARD_16 0x4 +#define OFDM_SC_RA_RAM_OP_PARAM_GUARD_8 0x8 +#define OFDM_SC_RA_RAM_OP_PARAM_GUARD_4 0xC +#define OFDM_SC_RA_RAM_OP_PARAM_CONST_QPSK 0x0 +#define OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM16 0x10 +#define OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64 0x20 +#define OFDM_SC_RA_RAM_OP_PARAM_HIER_NO 0x0 +#define OFDM_SC_RA_RAM_OP_PARAM_HIER_A1 0x40 +#define OFDM_SC_RA_RAM_OP_PARAM_HIER_A2 0x80 +#define OFDM_SC_RA_RAM_OP_PARAM_HIER_A4 0xC0 +#define OFDM_SC_RA_RAM_OP_PARAM_RATE_1_2 0x0 +#define OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3 0x200 +#define OFDM_SC_RA_RAM_OP_PARAM_RATE_3_4 0x400 +#define OFDM_SC_RA_RAM_OP_PARAM_RATE_5_6 0x600 +#define OFDM_SC_RA_RAM_OP_PARAM_RATE_7_8 0x800 +#define OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI 0x0 +#define OFDM_SC_RA_RAM_OP_PARAM_PRIO_LO 0x1000 +#define OFDM_SC_RA_RAM_OP_AUTO_MODE__M 0x1 +#define OFDM_SC_RA_RAM_OP_AUTO_GUARD__M 0x2 +#define OFDM_SC_RA_RAM_OP_AUTO_CONST__M 0x4 +#define OFDM_SC_RA_RAM_OP_AUTO_HIER__M 0x8 +#define OFDM_SC_RA_RAM_OP_AUTO_RATE__M 0x10 +#define OFDM_SC_RA_RAM_LOCK__A 0x3C2004B +#define OFDM_SC_RA_RAM_LOCK_DEMOD__M 0x1 +#define OFDM_SC_RA_RAM_LOCK_FEC__M 0x2 +#define OFDM_SC_RA_RAM_LOCK_MPEG__M 0x4 +#define OFDM_SC_RA_RAM_LOCK_NODVBT__M 0x8 +#define OFDM_SC_RA_RAM_BE_OPT_DELAY__A 0x3C2004D +#define OFDM_SC_RA_RAM_BE_OPT_INIT_DELAY__A 0x3C2004E +#define OFDM_SC_RA_RAM_ECHO_THRES__A 0x3C2004F +#define OFDM_SC_RA_RAM_ECHO_THRES_8K__B 0 +#define OFDM_SC_RA_RAM_ECHO_THRES_8K__M 0xFF +#define OFDM_SC_RA_RAM_ECHO_THRES_2K__B 8 +#define OFDM_SC_RA_RAM_ECHO_THRES_2K__M 0xFF00 +#define OFDM_SC_RA_RAM_CONFIG__A 0x3C20050 +#define OFDM_SC_RA_RAM_CONFIG_NE_FIX_ENABLE__M 0x800 +#define OFDM_SC_RA_RAM_FR_THRES_8K__A 0x3C2007D +#define OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A 0x3C200E0 +#define OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A 0x3C200E1 +#define OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A 0x3C200E3 +#define OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A 0x3C200E4 +#define OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A 0x3C200F8 +#define QAM_COMM_EXEC__A 0x1400000 +#define QAM_COMM_EXEC_STOP 0x0 +#define QAM_COMM_EXEC_ACTIVE 0x1 +#define QAM_TOP_ANNEX_A 0x0 +#define QAM_TOP_ANNEX_C 0x2 +#define QAM_SL_ERR_POWER__A 0x1430017 +#define QAM_DQ_QUAL_FUN0__A 0x1440018 +#define QAM_DQ_QUAL_FUN1__A 0x1440019 +#define QAM_DQ_QUAL_FUN2__A 0x144001A +#define QAM_DQ_QUAL_FUN3__A 0x144001B +#define QAM_DQ_QUAL_FUN4__A 0x144001C +#define QAM_DQ_QUAL_FUN5__A 0x144001D +#define QAM_LC_MODE__A 0x1450010 +#define QAM_LC_QUAL_TAB0__A 0x1450018 +#define QAM_LC_QUAL_TAB1__A 0x1450019 +#define QAM_LC_QUAL_TAB2__A 0x145001A +#define QAM_LC_QUAL_TAB3__A 0x145001B +#define QAM_LC_QUAL_TAB4__A 0x145001C +#define QAM_LC_QUAL_TAB5__A 0x145001D +#define QAM_LC_QUAL_TAB6__A 0x145001E +#define QAM_LC_QUAL_TAB8__A 0x145001F +#define QAM_LC_QUAL_TAB9__A 0x1450020 +#define QAM_LC_QUAL_TAB10__A 0x1450021 +#define QAM_LC_QUAL_TAB12__A 0x1450022 +#define QAM_LC_QUAL_TAB15__A 0x1450023 +#define QAM_LC_QUAL_TAB16__A 0x1450024 +#define QAM_LC_QUAL_TAB20__A 0x1450025 +#define QAM_LC_QUAL_TAB25__A 0x1450026 +#define QAM_LC_LPF_FACTORP__A 0x1450028 +#define QAM_LC_LPF_FACTORI__A 0x1450029 +#define QAM_LC_RATE_LIMIT__A 0x145002A +#define QAM_LC_SYMBOL_FREQ__A 0x145002B +#define QAM_SY_TIMEOUT__A 0x1470011 +#define QAM_SY_TIMEOUT__PRE 0x3A98 +#define QAM_SY_SYNC_LWM__A 0x1470012 +#define QAM_SY_SYNC_AWM__A 0x1470013 +#define QAM_SY_SYNC_HWM__A 0x1470014 +#define QAM_SY_SP_INV__A 0x1470017 +#define QAM_SY_SP_INV_SPECTRUM_INV_DIS 0x0 +#define SCU_COMM_EXEC__A 0x800000 +#define SCU_COMM_EXEC_STOP 0x0 +#define SCU_COMM_EXEC_ACTIVE 0x1 +#define SCU_COMM_EXEC_HOLD 0x2 +#define SCU_RAM_DRIVER_DEBUG__A 0x831EBF +#define SCU_RAM_QAM_FSM_STEP_PERIOD__A 0x831EC4 +#define SCU_RAM_GPIO__A 0x831EC7 +#define SCU_RAM_GPIO_HW_LOCK_IND_DISABLE 0x0 +#define SCU_RAM_AGC_CLP_CTRL_MODE__A 0x831EC8 +#define SCU_RAM_FEC_ACCUM_PKT_FAILURES__A 0x831ECB +#define SCU_RAM_FEC_PRE_RS_BER_FILTER_SH__A 0x831F05 +#define SCU_RAM_AGC_FAST_SNS_CTRL_DELAY__A 0x831F15 +#define SCU_RAM_AGC_KI_CYCLEN__A 0x831F17 +#define SCU_RAM_AGC_SNS_CYCLEN__A 0x831F18 +#define SCU_RAM_AGC_RF_SNS_DEV_MAX__A 0x831F19 +#define SCU_RAM_AGC_RF_SNS_DEV_MIN__A 0x831F1A +#define SCU_RAM_AGC_RF_MAX__A 0x831F1B +#define SCU_RAM_AGC_CONFIG__A 0x831F24 +#define SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M 0x1 +#define SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M 0x2 +#define SCU_RAM_AGC_CONFIG_INV_IF_POL__M 0x100 +#define SCU_RAM_AGC_CONFIG_INV_RF_POL__M 0x200 +#define SCU_RAM_AGC_KI__A 0x831F25 +#define SCU_RAM_AGC_KI_RF__B 4 +#define SCU_RAM_AGC_KI_RF__M 0xF0 +#define SCU_RAM_AGC_KI_IF__B 8 +#define SCU_RAM_AGC_KI_IF__M 0xF00 +#define SCU_RAM_AGC_KI_RED__A 0x831F26 +#define SCU_RAM_AGC_KI_RED_RAGC_RED__B 2 +#define SCU_RAM_AGC_KI_RED_RAGC_RED__M 0xC +#define SCU_RAM_AGC_KI_RED_IAGC_RED__B 4 +#define SCU_RAM_AGC_KI_RED_IAGC_RED__M 0x30 +#define SCU_RAM_AGC_KI_INNERGAIN_MIN__A 0x831F27 +#define SCU_RAM_AGC_KI_MINGAIN__A 0x831F28 +#define SCU_RAM_AGC_KI_MAXGAIN__A 0x831F29 +#define SCU_RAM_AGC_KI_MAXMINGAIN_TH__A 0x831F2A +#define SCU_RAM_AGC_KI_MIN__A 0x831F2B +#define SCU_RAM_AGC_KI_MAX__A 0x831F2C +#define SCU_RAM_AGC_CLP_SUM__A 0x831F2D +#define SCU_RAM_AGC_CLP_SUM_MIN__A 0x831F2E +#define SCU_RAM_AGC_CLP_SUM_MAX__A 0x831F2F +#define SCU_RAM_AGC_CLP_CYCLEN__A 0x831F30 +#define SCU_RAM_AGC_CLP_CYCCNT__A 0x831F31 +#define SCU_RAM_AGC_CLP_DIR_TO__A 0x831F32 +#define SCU_RAM_AGC_CLP_DIR_WD__A 0x831F33 +#define SCU_RAM_AGC_CLP_DIR_STP__A 0x831F34 +#define SCU_RAM_AGC_SNS_SUM__A 0x831F35 +#define SCU_RAM_AGC_SNS_SUM_MIN__A 0x831F36 +#define SCU_RAM_AGC_SNS_SUM_MAX__A 0x831F37 +#define SCU_RAM_AGC_SNS_CYCCNT__A 0x831F38 +#define SCU_RAM_AGC_SNS_DIR_TO__A 0x831F39 +#define SCU_RAM_AGC_SNS_DIR_WD__A 0x831F3A +#define SCU_RAM_AGC_SNS_DIR_STP__A 0x831F3B +#define SCU_RAM_AGC_INGAIN_TGT__A 0x831F3D +#define SCU_RAM_AGC_INGAIN_TGT_MIN__A 0x831F3E +#define SCU_RAM_AGC_INGAIN_TGT_MAX__A 0x831F3F +#define SCU_RAM_AGC_IF_IACCU_HI__A 0x831F40 +#define SCU_RAM_AGC_IF_IACCU_LO__A 0x831F41 +#define SCU_RAM_AGC_IF_IACCU_HI_TGT__A 0x831F42 +#define SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__A 0x831F43 +#define SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A 0x831F44 +#define SCU_RAM_AGC_RF_IACCU_HI__A 0x831F45 +#define SCU_RAM_AGC_RF_IACCU_LO__A 0x831F46 +#define SCU_RAM_AGC_RF_IACCU_HI_CO__A 0x831F47 +#define SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A 0x831F84 +#define SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A 0x831F85 +#define SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A 0x831F86 +#define SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A 0x831F87 +#define SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A 0x831F88 +#define SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A 0x831F89 +#define SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A 0x831F8A +#define SCU_RAM_QAM_FSM_RTH__A 0x831F8E +#define SCU_RAM_QAM_FSM_FTH__A 0x831F8F +#define SCU_RAM_QAM_FSM_PTH__A 0x831F90 +#define SCU_RAM_QAM_FSM_MTH__A 0x831F91 +#define SCU_RAM_QAM_FSM_CTH__A 0x831F92 +#define SCU_RAM_QAM_FSM_QTH__A 0x831F93 +#define SCU_RAM_QAM_FSM_RATE_LIM__A 0x831F94 +#define SCU_RAM_QAM_FSM_FREQ_LIM__A 0x831F95 +#define SCU_RAM_QAM_FSM_COUNT_LIM__A 0x831F96 +#define SCU_RAM_QAM_LC_CA_COARSE__A 0x831F97 +#define SCU_RAM_QAM_LC_CA_FINE__A 0x831F99 +#define SCU_RAM_QAM_LC_CP_COARSE__A 0x831F9A +#define SCU_RAM_QAM_LC_CP_MEDIUM__A 0x831F9B +#define SCU_RAM_QAM_LC_CP_FINE__A 0x831F9C +#define SCU_RAM_QAM_LC_CI_COARSE__A 0x831F9D +#define SCU_RAM_QAM_LC_CI_MEDIUM__A 0x831F9E +#define SCU_RAM_QAM_LC_CI_FINE__A 0x831F9F +#define SCU_RAM_QAM_LC_EP_COARSE__A 0x831FA0 +#define SCU_RAM_QAM_LC_EP_MEDIUM__A 0x831FA1 +#define SCU_RAM_QAM_LC_EP_FINE__A 0x831FA2 +#define SCU_RAM_QAM_LC_EI_COARSE__A 0x831FA3 +#define SCU_RAM_QAM_LC_EI_MEDIUM__A 0x831FA4 +#define SCU_RAM_QAM_LC_EI_FINE__A 0x831FA5 +#define SCU_RAM_QAM_LC_CF_COARSE__A 0x831FA6 +#define SCU_RAM_QAM_LC_CF_MEDIUM__A 0x831FA7 +#define SCU_RAM_QAM_LC_CF_FINE__A 0x831FA8 +#define SCU_RAM_QAM_LC_CF1_COARSE__A 0x831FA9 +#define SCU_RAM_QAM_LC_CF1_MEDIUM__A 0x831FAA +#define SCU_RAM_QAM_LC_CF1_FINE__A 0x831FAB +#define SCU_RAM_QAM_SL_SIG_POWER__A 0x831FAC +#define SCU_RAM_QAM_EQ_CMA_RAD0__A 0x831FAD +#define SCU_RAM_QAM_EQ_CMA_RAD1__A 0x831FAE +#define SCU_RAM_QAM_EQ_CMA_RAD2__A 0x831FAF +#define SCU_RAM_QAM_EQ_CMA_RAD3__A 0x831FB0 +#define SCU_RAM_QAM_EQ_CMA_RAD4__A 0x831FB1 +#define SCU_RAM_QAM_EQ_CMA_RAD5__A 0x831FB2 +#define SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED 0x4000 +#define SCU_RAM_QAM_LOCKED_LOCKED_LOCKED 0x8000 +#define SCU_RAM_QAM_LOCKED_LOCKED_NEVER_LOCK 0xC000 +#define SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A 0x831FEA +#define SCU_RAM_DRIVER_VER_HI__A 0x831FEB +#define SCU_RAM_DRIVER_VER_LO__A 0x831FEC +#define SCU_RAM_PARAM_15__A 0x831FED +#define SCU_RAM_PARAM_0__A 0x831FFC +#define SCU_RAM_COMMAND__A 0x831FFD +#define SCU_RAM_COMMAND_CMD_DEMOD_RESET 0x1 +#define SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV 0x2 +#define SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM 0x3 +#define SCU_RAM_COMMAND_CMD_DEMOD_START 0x4 +#define SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK 0x5 +#define SCU_RAM_COMMAND_CMD_DEMOD_STOP 0x9 +#define SCU_RAM_COMMAND_STANDARD_QAM 0x200 +#define SCU_RAM_COMMAND_STANDARD_OFDM 0x400 +#define SIO_TOP_COMM_KEY__A 0x41000F +#define SIO_TOP_COMM_KEY_KEY 0xFABA +#define SIO_TOP_JTAGID_LO__A 0x410012 +#define SIO_HI_RA_RAM_RES__A 0x420031 +#define SIO_HI_RA_RAM_CMD__A 0x420032 +#define SIO_HI_RA_RAM_CMD_RESET 0x2 +#define SIO_HI_RA_RAM_CMD_CONFIG 0x3 +#define SIO_HI_RA_RAM_CMD_BRDCTRL 0x7 +#define SIO_HI_RA_RAM_PAR_1__A 0x420033 +#define SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY 0x3945 +#define SIO_HI_RA_RAM_PAR_2__A 0x420034 +#define SIO_HI_RA_RAM_PAR_2_CFG_DIV__M 0x7F +#define SIO_HI_RA_RAM_PAR_2_BRD_CFG_OPEN 0x0 +#define SIO_HI_RA_RAM_PAR_2_BRD_CFG_CLOSED 0x4 +#define SIO_HI_RA_RAM_PAR_3__A 0x420035 +#define SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M 0x7F +#define SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__B 7 +#define SIO_HI_RA_RAM_PAR_3_ACP_RW_READ 0x0 +#define SIO_HI_RA_RAM_PAR_3_ACP_RW_WRITE 0x8 +#define SIO_HI_RA_RAM_PAR_4__A 0x420036 +#define SIO_HI_RA_RAM_PAR_5__A 0x420037 +#define SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE 0x1 +#define SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M 0x8 +#define SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ 0x8 +#define SIO_HI_RA_RAM_PAR_6__A 0x420038 +#define SIO_CC_PLL_LOCK__A 0x450012 +#define SIO_CC_PWD_MODE__A 0x450015 +#define SIO_CC_PWD_MODE_LEVEL_NONE 0x0 +#define SIO_CC_PWD_MODE_LEVEL_OFDM 0x1 +#define SIO_CC_PWD_MODE_LEVEL_CLOCK 0x2 +#define SIO_CC_PWD_MODE_LEVEL_PLL 0x3 +#define SIO_CC_PWD_MODE_LEVEL_OSC 0x4 +#define SIO_CC_SOFT_RST__A 0x450016 +#define SIO_CC_SOFT_RST_OFDM__M 0x1 +#define SIO_CC_SOFT_RST_SYS__M 0x2 +#define SIO_CC_SOFT_RST_OSC__M 0x4 +#define SIO_CC_UPDATE__A 0x450017 +#define SIO_CC_UPDATE_KEY 0xFABA +#define SIO_OFDM_SH_OFDM_RING_ENABLE__A 0x470010 +#define SIO_OFDM_SH_OFDM_RING_ENABLE_OFF 0x0 +#define SIO_OFDM_SH_OFDM_RING_ENABLE_ON 0x1 +#define SIO_OFDM_SH_OFDM_RING_STATUS__A 0x470012 +#define SIO_OFDM_SH_OFDM_RING_STATUS_DOWN 0x0 +#define SIO_OFDM_SH_OFDM_RING_STATUS_ENABLED 0x1 +#define SIO_BL_COMM_EXEC__A 0x480000 +#define SIO_BL_COMM_EXEC_ACTIVE 0x1 +#define SIO_BL_STATUS__A 0x480010 +#define SIO_BL_MODE__A 0x480011 +#define SIO_BL_MODE_DIRECT 0x0 +#define SIO_BL_MODE_CHAIN 0x1 +#define SIO_BL_ENABLE__A 0x480012 +#define SIO_BL_ENABLE_ON 0x1 +#define SIO_BL_TGT_HDR__A 0x480014 +#define SIO_BL_TGT_ADDR__A 0x480015 +#define SIO_BL_SRC_ADDR__A 0x480016 +#define SIO_BL_SRC_LEN__A 0x480017 +#define SIO_BL_CHAIN_ADDR__A 0x480018 +#define SIO_BL_CHAIN_LEN__A 0x480019 +#define SIO_PDR_MON_CFG__A 0x7F0010 +#define SIO_PDR_UIO_IN_HI__A 0x7F0015 +#define SIO_PDR_UIO_OUT_LO__A 0x7F0016 +#define SIO_PDR_OHW_CFG__A 0x7F001F +#define SIO_PDR_OHW_CFG_FREF_SEL__M 0x3 +#define SIO_PDR_MSTRT_CFG__A 0x7F0025 +#define SIO_PDR_MERR_CFG__A 0x7F0026 +#define SIO_PDR_MCLK_CFG__A 0x7F0028 +#define SIO_PDR_MCLK_CFG_DRIVE__B 3 +#define SIO_PDR_MVAL_CFG__A 0x7F0029 +#define SIO_PDR_MD0_CFG__A 0x7F002A +#define SIO_PDR_MD0_CFG_DRIVE__B 3 +#define SIO_PDR_MD1_CFG__A 0x7F002B +#define SIO_PDR_MD2_CFG__A 0x7F002C +#define SIO_PDR_MD3_CFG__A 0x7F002D +#define SIO_PDR_MD4_CFG__A 0x7F002F +#define SIO_PDR_MD5_CFG__A 0x7F0030 +#define SIO_PDR_MD6_CFG__A 0x7F0031 +#define SIO_PDR_MD7_CFG__A 0x7F0032 +#define SIO_PDR_SMA_TX_CFG__A 0x7F0038 diff --git a/drivers/media/dvb/frontends/itd1000.c b/drivers/media/dvb/frontends/itd1000.c index f7a40a18777a0e13a90dfdc7f4e75ce87a952955..aa9ccb821fa51fe9a6f8612c5cbb491f065f7c2f 100644 --- a/drivers/media/dvb/frontends/itd1000.c +++ b/drivers/media/dvb/frontends/itd1000.c @@ -35,21 +35,18 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); -#define deb(args...) do { \ +#define itd_dbg(args...) do { \ if (debug) { \ printk(KERN_DEBUG "ITD1000: " args);\ - printk("\n"); \ } \ } while (0) -#define warn(args...) do { \ +#define itd_warn(args...) do { \ printk(KERN_WARNING "ITD1000: " args); \ - printk("\n"); \ } while (0) -#define info(args...) do { \ +#define itd_info(args...) do { \ printk(KERN_INFO "ITD1000: " args); \ - printk("\n"); \ } while (0) /* don't write more than one byte with flexcop behind */ @@ -62,7 +59,7 @@ static int itd1000_write_regs(struct itd1000_state *state, u8 reg, u8 v[], u8 le buf[0] = reg; memcpy(&buf[1], v, len); - /* deb("wr %02x: %02x", reg, v[0]); */ + /* itd_dbg("wr %02x: %02x\n", reg, v[0]); */ if (i2c_transfer(state->i2c, &msg, 1) != 1) { printk(KERN_WARNING "itd1000 I2C write failed\n"); @@ -83,7 +80,7 @@ static int itd1000_read_reg(struct itd1000_state *state, u8 reg) itd1000_write_regs(state, (reg - 1) & 0xff, &state->shadow[(reg - 1) & 0xff], 1); if (i2c_transfer(state->i2c, msg, 2) != 2) { - warn("itd1000 I2C read failed"); + itd_warn("itd1000 I2C read failed\n"); return -EREMOTEIO; } return val; @@ -127,14 +124,14 @@ static void itd1000_set_lpf_bw(struct itd1000_state *state, u32 symbol_rate) u8 bbgvmin = itd1000_read_reg(state, BBGVMIN) & 0xf0; u8 bw = itd1000_read_reg(state, BW) & 0xf0; - deb("symbol_rate = %d", symbol_rate); + itd_dbg("symbol_rate = %d\n", symbol_rate); /* not sure what is that ? - starting to download the table */ itd1000_write_reg(state, CON1, con1 | (1 << 1)); for (i = 0; i < ARRAY_SIZE(itd1000_lpf_pga); i++) if (symbol_rate < itd1000_lpf_pga[i].symbol_rate) { - deb("symrate: index: %d pgaext: %x, bbgvmin: %x", i, itd1000_lpf_pga[i].pgaext, itd1000_lpf_pga[i].bbgvmin); + itd_dbg("symrate: index: %d pgaext: %x, bbgvmin: %x\n", i, itd1000_lpf_pga[i].pgaext, itd1000_lpf_pga[i].bbgvmin); itd1000_write_reg(state, PLLFH, pllfh | (itd1000_lpf_pga[i].pgaext << 4)); itd1000_write_reg(state, BBGVMIN, bbgvmin | (itd1000_lpf_pga[i].bbgvmin)); itd1000_write_reg(state, BW, bw | (i & 0x0f)); @@ -182,7 +179,7 @@ static void itd1000_set_vco(struct itd1000_state *state, u32 freq_khz) adcout = itd1000_read_reg(state, PLLLOCK) & 0x0f; - deb("VCO: %dkHz: %d -> ADCOUT: %d %02x", freq_khz, itd1000_vcorg[i].vcorg, adcout, vco_chp1_i2c); + itd_dbg("VCO: %dkHz: %d -> ADCOUT: %d %02x\n", freq_khz, itd1000_vcorg[i].vcorg, adcout, vco_chp1_i2c); if (adcout > 13) { if (!(itd1000_vcorg[i].vcorg == 7 || itd1000_vcorg[i].vcorg == 15)) @@ -232,7 +229,7 @@ static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz) pllf = (u32) tmp; state->frequency = ((plln * 1000) + (pllf * 1000)/1048576) * 2*FREF; - deb("frequency: %dkHz (wanted) %dkHz (set), PLLF = %d, PLLN = %d", freq_khz, state->frequency, pllf, plln); + itd_dbg("frequency: %dkHz (wanted) %dkHz (set), PLLF = %d, PLLN = %d\n", freq_khz, state->frequency, pllf, plln); itd1000_write_reg(state, PLLNH, 0x80); /* PLLNH */; itd1000_write_reg(state, PLLNL, plln & 0xff); @@ -242,7 +239,7 @@ static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz) for (i = 0; i < ARRAY_SIZE(itd1000_fre_values); i++) { if (freq_khz <= itd1000_fre_values[i].freq) { - deb("fre_values: %d", i); + itd_dbg("fre_values: %d\n", i); itd1000_write_reg(state, RFTR, itd1000_fre_values[i].values[0]); for (j = 0; j < 9; j++) itd1000_write_reg(state, RFST1+j, itd1000_fre_values[i].values[j+1]); @@ -382,7 +379,7 @@ struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter kfree(state); return NULL; } - info("successfully identified (ID: %d)", i); + itd_info("successfully identified (ID: %d)\n", i); memset(state->shadow, 0xff, sizeof(state->shadow)); for (i = 0x65; i < 0x9c; i++) diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c index a763ec756f7f84df840bcb38bfb3816ee016e174..6599b8fea9e9ad0d2c3bad2560565670b5e2486c 100644 --- a/drivers/media/dvb/frontends/nxt6000.c +++ b/drivers/media/dvb/frontends/nxt6000.c @@ -50,7 +50,7 @@ static int nxt6000_writereg(struct nxt6000_state* state, u8 reg, u8 data) if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) dprintk("nxt6000: nxt6000_write error (reg: 0x%02X, data: 0x%02X, ret: %d)\n", reg, data, ret); - return (ret != 1) ? -EFAULT : 0; + return (ret != 1) ? -EIO : 0; } static u8 nxt6000_readreg(struct nxt6000_state* state, u8 reg) diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index 17f8cdf8afefe041a3be5ecbd11cf009f93f0e3f..3879d2e378aa73da4ac1b923a7e163c6c54a48a6 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -634,7 +634,7 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, struct s5h1420_state* state = fe->demodulator_priv; int frequency_delta; struct dvb_frontend_tune_settings fesettings; - uint8_t clock_settting; + uint8_t clock_setting; dprintk("enter %s\n", __func__); @@ -684,19 +684,19 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, switch (state->fclk) { default: case 88000000: - clock_settting = 80; + clock_setting = 80; break; case 86000000: - clock_settting = 78; + clock_setting = 78; break; case 80000000: - clock_settting = 72; + clock_setting = 72; break; case 59000000: - clock_settting = 51; + clock_setting = 51; break; case 44000000: - clock_settting = 36; + clock_setting = 36; break; } dprintk("pll01: %d, ToneFreq: %d\n", state->fclk/1000000 - 8, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32)); diff --git a/drivers/media/dvb/frontends/tda18271c2dd.c b/drivers/media/dvb/frontends/tda18271c2dd.c new file mode 100644 index 0000000000000000000000000000000000000000..0384e8da4f5ea9ec66c83058031b1d1e52dffe8a --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271c2dd.c @@ -0,0 +1,1251 @@ +/* + * tda18271c2dd: Driver for the TDA18271C2 tuner + * + * Copyright (C) 2010 Digital Devices GmbH + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +struct SStandardParam { + s32 m_IFFrequency; + u32 m_BandWidth; + u8 m_EP3_4_0; + u8 m_EB22; +}; + +struct SMap { + u32 m_Frequency; + u8 m_Param; +}; + +struct SMapI { + u32 m_Frequency; + s32 m_Param; +}; + +struct SMap2 { + u32 m_Frequency; + u8 m_Param1; + u8 m_Param2; +}; + +struct SRFBandMap { + u32 m_RF_max; + u32 m_RF1_Default; + u32 m_RF2_Default; + u32 m_RF3_Default; +}; + +enum ERegister { + ID = 0, + TM, + PL, + EP1, EP2, EP3, EP4, EP5, + CPD, CD1, CD2, CD3, + MPD, MD1, MD2, MD3, + EB1, EB2, EB3, EB4, EB5, EB6, EB7, EB8, EB9, EB10, + EB11, EB12, EB13, EB14, EB15, EB16, EB17, EB18, EB19, EB20, + EB21, EB22, EB23, + NUM_REGS +}; + +struct tda_state { + struct i2c_adapter *i2c; + u8 adr; + + u32 m_Frequency; + u32 IF; + + u8 m_IFLevelAnalog; + u8 m_IFLevelDigital; + u8 m_IFLevelDVBC; + u8 m_IFLevelDVBT; + + u8 m_EP4; + u8 m_EP3_Standby; + + bool m_bMaster; + + s32 m_SettlingTime; + + u8 m_Regs[NUM_REGS]; + + /* Tracking filter settings for band 0..6 */ + u32 m_RF1[7]; + s32 m_RF_A1[7]; + s32 m_RF_B1[7]; + u32 m_RF2[7]; + s32 m_RF_A2[7]; + s32 m_RF_B2[7]; + u32 m_RF3[7]; + + u8 m_TMValue_RFCal; /* Calibration temperatur */ + + bool m_bFMInput; /* true to use Pin 8 for FM Radio */ + +}; + +static int PowerScan(struct tda_state *state, + u8 RFBand, u32 RF_in, + u32 *pRF_Out, bool *pbcal); + +static int i2c_readn(struct i2c_adapter *adapter, u8 adr, u8 *data, int len) +{ + struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, + .buf = data, .len = len} }; + return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; +} + +static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) +{ + struct i2c_msg msg = {.addr = adr, .flags = 0, + .buf = data, .len = len}; + + if (i2c_transfer(adap, &msg, 1) != 1) { + printk(KERN_ERR "tda18271c2dd: i2c write error at addr %i\n", adr); + return -1; + } + return 0; +} + +static int WriteRegs(struct tda_state *state, + u8 SubAddr, u8 *Regs, u16 nRegs) +{ + u8 data[nRegs+1]; + + data[0] = SubAddr; + memcpy(data + 1, Regs, nRegs); + return i2c_write(state->i2c, state->adr, data, nRegs+1); +} + +static int WriteReg(struct tda_state *state, u8 SubAddr, u8 Reg) +{ + u8 msg[2] = {SubAddr, Reg}; + + return i2c_write(state->i2c, state->adr, msg, 2); +} + +static int Read(struct tda_state *state, u8 * Regs) +{ + return i2c_readn(state->i2c, state->adr, Regs, 16); +} + +static int ReadExtented(struct tda_state *state, u8 * Regs) +{ + return i2c_readn(state->i2c, state->adr, Regs, NUM_REGS); +} + +static int UpdateRegs(struct tda_state *state, u8 RegFrom, u8 RegTo) +{ + return WriteRegs(state, RegFrom, + &state->m_Regs[RegFrom], RegTo-RegFrom+1); +} +static int UpdateReg(struct tda_state *state, u8 Reg) +{ + return WriteReg(state, Reg, state->m_Regs[Reg]); +} + +#include "tda18271c2dd_maps.h" + +static void reset(struct tda_state *state) +{ + u32 ulIFLevelAnalog = 0; + u32 ulIFLevelDigital = 2; + u32 ulIFLevelDVBC = 7; + u32 ulIFLevelDVBT = 6; + u32 ulXTOut = 0; + u32 ulStandbyMode = 0x06; /* Send in stdb, but leave osc on */ + u32 ulSlave = 0; + u32 ulFMInput = 0; + u32 ulSettlingTime = 100; + + state->m_Frequency = 0; + state->m_SettlingTime = 100; + state->m_IFLevelAnalog = (ulIFLevelAnalog & 0x07) << 2; + state->m_IFLevelDigital = (ulIFLevelDigital & 0x07) << 2; + state->m_IFLevelDVBC = (ulIFLevelDVBC & 0x07) << 2; + state->m_IFLevelDVBT = (ulIFLevelDVBT & 0x07) << 2; + + state->m_EP4 = 0x20; + if (ulXTOut != 0) + state->m_EP4 |= 0x40; + + state->m_EP3_Standby = ((ulStandbyMode & 0x07) << 5) | 0x0F; + state->m_bMaster = (ulSlave == 0); + + state->m_SettlingTime = ulSettlingTime; + + state->m_bFMInput = (ulFMInput == 2); +} + +static bool SearchMap1(struct SMap Map[], + u32 Frequency, u8 *pParam) +{ + int i = 0; + + while ((Map[i].m_Frequency != 0) && (Frequency > Map[i].m_Frequency)) + i += 1; + if (Map[i].m_Frequency == 0) + return false; + *pParam = Map[i].m_Param; + return true; +} + +static bool SearchMap2(struct SMapI Map[], + u32 Frequency, s32 *pParam) +{ + int i = 0; + + while ((Map[i].m_Frequency != 0) && + (Frequency > Map[i].m_Frequency)) + i += 1; + if (Map[i].m_Frequency == 0) + return false; + *pParam = Map[i].m_Param; + return true; +} + +static bool SearchMap3(struct SMap2 Map[], u32 Frequency, + u8 *pParam1, u8 *pParam2) +{ + int i = 0; + + while ((Map[i].m_Frequency != 0) && + (Frequency > Map[i].m_Frequency)) + i += 1; + if (Map[i].m_Frequency == 0) + return false; + *pParam1 = Map[i].m_Param1; + *pParam2 = Map[i].m_Param2; + return true; +} + +static bool SearchMap4(struct SRFBandMap Map[], + u32 Frequency, u8 *pRFBand) +{ + int i = 0; + + while (i < 7 && (Frequency > Map[i].m_RF_max)) + i += 1; + if (i == 7) + return false; + *pRFBand = i; + return true; +} + +static int ThermometerRead(struct tda_state *state, u8 *pTM_Value) +{ + int status = 0; + + do { + u8 Regs[16]; + state->m_Regs[TM] |= 0x10; + status = UpdateReg(state, TM); + if (status < 0) + break; + status = Read(state, Regs); + if (status < 0) + break; + if (((Regs[TM] & 0x0F) == 0 && (Regs[TM] & 0x20) == 0x20) || + ((Regs[TM] & 0x0F) == 8 && (Regs[TM] & 0x20) == 0x00)) { + state->m_Regs[TM] ^= 0x20; + status = UpdateReg(state, TM); + if (status < 0) + break; + msleep(10); + status = Read(state, Regs); + if (status < 0) + break; + } + *pTM_Value = (Regs[TM] & 0x20) + ? m_Thermometer_Map_2[Regs[TM] & 0x0F] + : m_Thermometer_Map_1[Regs[TM] & 0x0F] ; + state->m_Regs[TM] &= ~0x10; /* Thermometer off */ + status = UpdateReg(state, TM); + if (status < 0) + break; + state->m_Regs[EP4] &= ~0x03; /* CAL_mode = 0 ????????? */ + status = UpdateReg(state, EP4); + if (status < 0) + break; + } while (0); + + return status; +} + +static int StandBy(struct tda_state *state) +{ + int status = 0; + do { + state->m_Regs[EB12] &= ~0x20; /* PD_AGC1_Det = 0 */ + status = UpdateReg(state, EB12); + if (status < 0) + break; + state->m_Regs[EB18] &= ~0x83; /* AGC1_loop_off = 0, AGC1_Gain = 6 dB */ + status = UpdateReg(state, EB18); + if (status < 0) + break; + state->m_Regs[EB21] |= 0x03; /* AGC2_Gain = -6 dB */ + state->m_Regs[EP3] = state->m_EP3_Standby; + status = UpdateReg(state, EP3); + if (status < 0) + break; + state->m_Regs[EB23] &= ~0x06; /* ForceLP_Fc2_En = 0, LP_Fc[2] = 0 */ + status = UpdateRegs(state, EB21, EB23); + if (status < 0) + break; + } while (0); + return status; +} + +static int CalcMainPLL(struct tda_state *state, u32 freq) +{ + + u8 PostDiv; + u8 Div; + u64 OscFreq; + u32 MainDiv; + + if (!SearchMap3(m_Main_PLL_Map, freq, &PostDiv, &Div)) + return -EINVAL; + + OscFreq = (u64) freq * (u64) Div; + OscFreq *= (u64) 16384; + do_div(OscFreq, (u64)16000000); + MainDiv = OscFreq; + + state->m_Regs[MPD] = PostDiv & 0x77; + state->m_Regs[MD1] = ((MainDiv >> 16) & 0x7F); + state->m_Regs[MD2] = ((MainDiv >> 8) & 0xFF); + state->m_Regs[MD3] = (MainDiv & 0xFF); + + return UpdateRegs(state, MPD, MD3); +} + +static int CalcCalPLL(struct tda_state *state, u32 freq) +{ + u8 PostDiv; + u8 Div; + u64 OscFreq; + u32 CalDiv; + + if (!SearchMap3(m_Cal_PLL_Map, freq, &PostDiv, &Div)) + return -EINVAL; + + OscFreq = (u64)freq * (u64)Div; + /* CalDiv = u32( OscFreq * 16384 / 16000000 ); */ + OscFreq *= (u64)16384; + do_div(OscFreq, (u64)16000000); + CalDiv = OscFreq; + + state->m_Regs[CPD] = PostDiv; + state->m_Regs[CD1] = ((CalDiv >> 16) & 0xFF); + state->m_Regs[CD2] = ((CalDiv >> 8) & 0xFF); + state->m_Regs[CD3] = (CalDiv & 0xFF); + + return UpdateRegs(state, CPD, CD3); +} + +static int CalibrateRF(struct tda_state *state, + u8 RFBand, u32 freq, s32 *pCprog) +{ + int status = 0; + u8 Regs[NUM_REGS]; + do { + u8 BP_Filter = 0; + u8 GainTaper = 0; + u8 RFC_K = 0; + u8 RFC_M = 0; + + state->m_Regs[EP4] &= ~0x03; /* CAL_mode = 0 */ + status = UpdateReg(state, EP4); + if (status < 0) + break; + state->m_Regs[EB18] |= 0x03; /* AGC1_Gain = 3 */ + status = UpdateReg(state, EB18); + if (status < 0) + break; + + /* Switching off LT (as datasheet says) causes calibration on C1 to fail */ + /* (Readout of Cprog is allways 255) */ + if (state->m_Regs[ID] != 0x83) /* C1: ID == 83, C2: ID == 84 */ + state->m_Regs[EP3] |= 0x40; /* SM_LT = 1 */ + + if (!(SearchMap1(m_BP_Filter_Map, freq, &BP_Filter) && + SearchMap1(m_GainTaper_Map, freq, &GainTaper) && + SearchMap3(m_KM_Map, freq, &RFC_K, &RFC_M))) + return -EINVAL; + + state->m_Regs[EP1] = (state->m_Regs[EP1] & ~0x07) | BP_Filter; + state->m_Regs[EP2] = (RFBand << 5) | GainTaper; + + state->m_Regs[EB13] = (state->m_Regs[EB13] & ~0x7C) | (RFC_K << 4) | (RFC_M << 2); + + status = UpdateRegs(state, EP1, EP3); + if (status < 0) + break; + status = UpdateReg(state, EB13); + if (status < 0) + break; + + state->m_Regs[EB4] |= 0x20; /* LO_ForceSrce = 1 */ + status = UpdateReg(state, EB4); + if (status < 0) + break; + + state->m_Regs[EB7] |= 0x20; /* CAL_ForceSrce = 1 */ + status = UpdateReg(state, EB7); + if (status < 0) + break; + + state->m_Regs[EB14] = 0; /* RFC_Cprog = 0 */ + status = UpdateReg(state, EB14); + if (status < 0) + break; + + state->m_Regs[EB20] &= ~0x20; /* ForceLock = 0; */ + status = UpdateReg(state, EB20); + if (status < 0) + break; + + state->m_Regs[EP4] |= 0x03; /* CAL_Mode = 3 */ + status = UpdateRegs(state, EP4, EP5); + if (status < 0) + break; + + status = CalcCalPLL(state, freq); + if (status < 0) + break; + status = CalcMainPLL(state, freq + 1000000); + if (status < 0) + break; + + msleep(5); + status = UpdateReg(state, EP2); + if (status < 0) + break; + status = UpdateReg(state, EP1); + if (status < 0) + break; + status = UpdateReg(state, EP2); + if (status < 0) + break; + status = UpdateReg(state, EP1); + if (status < 0) + break; + + state->m_Regs[EB4] &= ~0x20; /* LO_ForceSrce = 0 */ + status = UpdateReg(state, EB4); + if (status < 0) + break; + + state->m_Regs[EB7] &= ~0x20; /* CAL_ForceSrce = 0 */ + status = UpdateReg(state, EB7); + if (status < 0) + break; + msleep(10); + + state->m_Regs[EB20] |= 0x20; /* ForceLock = 1; */ + status = UpdateReg(state, EB20); + if (status < 0) + break; + msleep(60); + + state->m_Regs[EP4] &= ~0x03; /* CAL_Mode = 0 */ + state->m_Regs[EP3] &= ~0x40; /* SM_LT = 0 */ + state->m_Regs[EB18] &= ~0x03; /* AGC1_Gain = 0 */ + status = UpdateReg(state, EB18); + if (status < 0) + break; + status = UpdateRegs(state, EP3, EP4); + if (status < 0) + break; + status = UpdateReg(state, EP1); + if (status < 0) + break; + + status = ReadExtented(state, Regs); + if (status < 0) + break; + + *pCprog = Regs[EB14]; + + } while (0); + return status; +} + +static int RFTrackingFiltersInit(struct tda_state *state, + u8 RFBand) +{ + int status = 0; + + u32 RF1 = m_RF_Band_Map[RFBand].m_RF1_Default; + u32 RF2 = m_RF_Band_Map[RFBand].m_RF2_Default; + u32 RF3 = m_RF_Band_Map[RFBand].m_RF3_Default; + bool bcal = false; + + s32 Cprog_cal1 = 0; + s32 Cprog_table1 = 0; + s32 Cprog_cal2 = 0; + s32 Cprog_table2 = 0; + s32 Cprog_cal3 = 0; + s32 Cprog_table3 = 0; + + state->m_RF_A1[RFBand] = 0; + state->m_RF_B1[RFBand] = 0; + state->m_RF_A2[RFBand] = 0; + state->m_RF_B2[RFBand] = 0; + + do { + status = PowerScan(state, RFBand, RF1, &RF1, &bcal); + if (status < 0) + break; + if (bcal) { + status = CalibrateRF(state, RFBand, RF1, &Cprog_cal1); + if (status < 0) + break; + } + SearchMap2(m_RF_Cal_Map, RF1, &Cprog_table1); + if (!bcal) + Cprog_cal1 = Cprog_table1; + state->m_RF_B1[RFBand] = Cprog_cal1 - Cprog_table1; + /* state->m_RF_A1[RF_Band] = ???? */ + + if (RF2 == 0) + break; + + status = PowerScan(state, RFBand, RF2, &RF2, &bcal); + if (status < 0) + break; + if (bcal) { + status = CalibrateRF(state, RFBand, RF2, &Cprog_cal2); + if (status < 0) + break; + } + SearchMap2(m_RF_Cal_Map, RF2, &Cprog_table2); + if (!bcal) + Cprog_cal2 = Cprog_table2; + + state->m_RF_A1[RFBand] = + (Cprog_cal2 - Cprog_table2 - Cprog_cal1 + Cprog_table1) / + ((s32)(RF2) - (s32)(RF1)); + + if (RF3 == 0) + break; + + status = PowerScan(state, RFBand, RF3, &RF3, &bcal); + if (status < 0) + break; + if (bcal) { + status = CalibrateRF(state, RFBand, RF3, &Cprog_cal3); + if (status < 0) + break; + } + SearchMap2(m_RF_Cal_Map, RF3, &Cprog_table3); + if (!bcal) + Cprog_cal3 = Cprog_table3; + state->m_RF_A2[RFBand] = (Cprog_cal3 - Cprog_table3 - Cprog_cal2 + Cprog_table2) / ((s32)(RF3) - (s32)(RF2)); + state->m_RF_B2[RFBand] = Cprog_cal2 - Cprog_table2; + + } while (0); + + state->m_RF1[RFBand] = RF1; + state->m_RF2[RFBand] = RF2; + state->m_RF3[RFBand] = RF3; + +#if 0 + printk(KERN_ERR "tda18271c2dd: %s %d RF1 = %d A1 = %d B1 = %d RF2 = %d A2 = %d B2 = %d RF3 = %d\n", __func__, + RFBand, RF1, state->m_RF_A1[RFBand], state->m_RF_B1[RFBand], RF2, + state->m_RF_A2[RFBand], state->m_RF_B2[RFBand], RF3); +#endif + + return status; +} + +static int PowerScan(struct tda_state *state, + u8 RFBand, u32 RF_in, u32 *pRF_Out, bool *pbcal) +{ + int status = 0; + do { + u8 Gain_Taper = 0; + s32 RFC_Cprog = 0; + u8 CID_Target = 0; + u8 CountLimit = 0; + u32 freq_MainPLL; + u8 Regs[NUM_REGS]; + u8 CID_Gain; + s32 Count = 0; + int sign = 1; + bool wait = false; + + if (!(SearchMap2(m_RF_Cal_Map, RF_in, &RFC_Cprog) && + SearchMap1(m_GainTaper_Map, RF_in, &Gain_Taper) && + SearchMap3(m_CID_Target_Map, RF_in, &CID_Target, &CountLimit))) { + + printk(KERN_ERR "tda18271c2dd: %s Search map failed\n", __func__); + return -EINVAL; + } + + state->m_Regs[EP2] = (RFBand << 5) | Gain_Taper; + state->m_Regs[EB14] = (RFC_Cprog); + status = UpdateReg(state, EP2); + if (status < 0) + break; + status = UpdateReg(state, EB14); + if (status < 0) + break; + + freq_MainPLL = RF_in + 1000000; + status = CalcMainPLL(state, freq_MainPLL); + if (status < 0) + break; + msleep(5); + state->m_Regs[EP4] = (state->m_Regs[EP4] & ~0x03) | 1; /* CAL_mode = 1 */ + status = UpdateReg(state, EP4); + if (status < 0) + break; + status = UpdateReg(state, EP2); /* Launch power measurement */ + if (status < 0) + break; + status = ReadExtented(state, Regs); + if (status < 0) + break; + CID_Gain = Regs[EB10] & 0x3F; + state->m_Regs[ID] = Regs[ID]; /* Chip version, (needed for C1 workarround in CalibrateRF) */ + + *pRF_Out = RF_in; + + while (CID_Gain < CID_Target) { + freq_MainPLL = RF_in + sign * Count + 1000000; + status = CalcMainPLL(state, freq_MainPLL); + if (status < 0) + break; + msleep(wait ? 5 : 1); + wait = false; + status = UpdateReg(state, EP2); /* Launch power measurement */ + if (status < 0) + break; + status = ReadExtented(state, Regs); + if (status < 0) + break; + CID_Gain = Regs[EB10] & 0x3F; + Count += 200000; + + if (Count < CountLimit * 100000) + continue; + if (sign < 0) + break; + + sign = -sign; + Count = 200000; + wait = true; + } + status = status; + if (status < 0) + break; + if (CID_Gain >= CID_Target) { + *pbcal = true; + *pRF_Out = freq_MainPLL - 1000000; + } else + *pbcal = false; + } while (0); + + return status; +} + +static int PowerScanInit(struct tda_state *state) +{ + int status = 0; + do { + state->m_Regs[EP3] = (state->m_Regs[EP3] & ~0x1F) | 0x12; + state->m_Regs[EP4] = (state->m_Regs[EP4] & ~0x1F); /* If level = 0, Cal mode = 0 */ + status = UpdateRegs(state, EP3, EP4); + if (status < 0) + break; + state->m_Regs[EB18] = (state->m_Regs[EB18] & ~0x03); /* AGC 1 Gain = 0 */ + status = UpdateReg(state, EB18); + if (status < 0) + break; + state->m_Regs[EB21] = (state->m_Regs[EB21] & ~0x03); /* AGC 2 Gain = 0 (Datasheet = 3) */ + state->m_Regs[EB23] = (state->m_Regs[EB23] | 0x06); /* ForceLP_Fc2_En = 1, LPFc[2] = 1 */ + status = UpdateRegs(state, EB21, EB23); + if (status < 0) + break; + } while (0); + return status; +} + +static int CalcRFFilterCurve(struct tda_state *state) +{ + int status = 0; + do { + msleep(200); /* Temperature stabilisation */ + status = PowerScanInit(state); + if (status < 0) + break; + status = RFTrackingFiltersInit(state, 0); + if (status < 0) + break; + status = RFTrackingFiltersInit(state, 1); + if (status < 0) + break; + status = RFTrackingFiltersInit(state, 2); + if (status < 0) + break; + status = RFTrackingFiltersInit(state, 3); + if (status < 0) + break; + status = RFTrackingFiltersInit(state, 4); + if (status < 0) + break; + status = RFTrackingFiltersInit(state, 5); + if (status < 0) + break; + status = RFTrackingFiltersInit(state, 6); + if (status < 0) + break; + status = ThermometerRead(state, &state->m_TMValue_RFCal); /* also switches off Cal mode !!! */ + if (status < 0) + break; + } while (0); + + return status; +} + +static int FixedContentsI2CUpdate(struct tda_state *state) +{ + static u8 InitRegs[] = { + 0x08, 0x80, 0xC6, + 0xDF, 0x16, 0x60, 0x80, + 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xFC, 0x01, 0x84, 0x41, + 0x01, 0x84, 0x40, 0x07, + 0x00, 0x00, 0x96, 0x3F, + 0xC1, 0x00, 0x8F, 0x00, + 0x00, 0x8C, 0x00, 0x20, + 0xB3, 0x48, 0xB0, + }; + int status = 0; + memcpy(&state->m_Regs[TM], InitRegs, EB23 - TM + 1); + do { + status = UpdateRegs(state, TM, EB23); + if (status < 0) + break; + + /* AGC1 gain setup */ + state->m_Regs[EB17] = 0x00; + status = UpdateReg(state, EB17); + if (status < 0) + break; + state->m_Regs[EB17] = 0x03; + status = UpdateReg(state, EB17); + if (status < 0) + break; + state->m_Regs[EB17] = 0x43; + status = UpdateReg(state, EB17); + if (status < 0) + break; + state->m_Regs[EB17] = 0x4C; + status = UpdateReg(state, EB17); + if (status < 0) + break; + + /* IRC Cal Low band */ + state->m_Regs[EP3] = 0x1F; + state->m_Regs[EP4] = 0x66; + state->m_Regs[EP5] = 0x81; + state->m_Regs[CPD] = 0xCC; + state->m_Regs[CD1] = 0x6C; + state->m_Regs[CD2] = 0x00; + state->m_Regs[CD3] = 0x00; + state->m_Regs[MPD] = 0xC5; + state->m_Regs[MD1] = 0x77; + state->m_Regs[MD2] = 0x08; + state->m_Regs[MD3] = 0x00; + status = UpdateRegs(state, EP2, MD3); /* diff between sw and datasheet (ep3-md3) */ + if (status < 0) + break; + +#if 0 + state->m_Regs[EB4] = 0x61; /* missing in sw */ + status = UpdateReg(state, EB4); + if (status < 0) + break; + msleep(1); + state->m_Regs[EB4] = 0x41; + status = UpdateReg(state, EB4); + if (status < 0) + break; +#endif + + msleep(5); + status = UpdateReg(state, EP1); + if (status < 0) + break; + msleep(5); + + state->m_Regs[EP5] = 0x85; + state->m_Regs[CPD] = 0xCB; + state->m_Regs[CD1] = 0x66; + state->m_Regs[CD2] = 0x70; + status = UpdateRegs(state, EP3, CD3); + if (status < 0) + break; + msleep(5); + status = UpdateReg(state, EP2); + if (status < 0) + break; + msleep(30); + + /* IRC Cal mid band */ + state->m_Regs[EP5] = 0x82; + state->m_Regs[CPD] = 0xA8; + state->m_Regs[CD2] = 0x00; + state->m_Regs[MPD] = 0xA1; /* Datasheet = 0xA9 */ + state->m_Regs[MD1] = 0x73; + state->m_Regs[MD2] = 0x1A; + status = UpdateRegs(state, EP3, MD3); + if (status < 0) + break; + + msleep(5); + status = UpdateReg(state, EP1); + if (status < 0) + break; + msleep(5); + + state->m_Regs[EP5] = 0x86; + state->m_Regs[CPD] = 0xA8; + state->m_Regs[CD1] = 0x66; + state->m_Regs[CD2] = 0xA0; + status = UpdateRegs(state, EP3, CD3); + if (status < 0) + break; + msleep(5); + status = UpdateReg(state, EP2); + if (status < 0) + break; + msleep(30); + + /* IRC Cal high band */ + state->m_Regs[EP5] = 0x83; + state->m_Regs[CPD] = 0x98; + state->m_Regs[CD1] = 0x65; + state->m_Regs[CD2] = 0x00; + state->m_Regs[MPD] = 0x91; /* Datasheet = 0x91 */ + state->m_Regs[MD1] = 0x71; + state->m_Regs[MD2] = 0xCD; + status = UpdateRegs(state, EP3, MD3); + if (status < 0) + break; + msleep(5); + status = UpdateReg(state, EP1); + if (status < 0) + break; + msleep(5); + state->m_Regs[EP5] = 0x87; + state->m_Regs[CD1] = 0x65; + state->m_Regs[CD2] = 0x50; + status = UpdateRegs(state, EP3, CD3); + if (status < 0) + break; + msleep(5); + status = UpdateReg(state, EP2); + if (status < 0) + break; + msleep(30); + + /* Back to normal */ + state->m_Regs[EP4] = 0x64; + status = UpdateReg(state, EP4); + if (status < 0) + break; + status = UpdateReg(state, EP1); + if (status < 0) + break; + + } while (0); + return status; +} + +static int InitCal(struct tda_state *state) +{ + int status = 0; + + do { + status = FixedContentsI2CUpdate(state); + if (status < 0) + break; + status = CalcRFFilterCurve(state); + if (status < 0) + break; + status = StandBy(state); + if (status < 0) + break; + /* m_bInitDone = true; */ + } while (0); + return status; +}; + +static int RFTrackingFiltersCorrection(struct tda_state *state, + u32 Frequency) +{ + int status = 0; + s32 Cprog_table; + u8 RFBand; + u8 dCoverdT; + + if (!SearchMap2(m_RF_Cal_Map, Frequency, &Cprog_table) || + !SearchMap4(m_RF_Band_Map, Frequency, &RFBand) || + !SearchMap1(m_RF_Cal_DC_Over_DT_Map, Frequency, &dCoverdT)) + + return -EINVAL; + + do { + u8 TMValue_Current; + u32 RF1 = state->m_RF1[RFBand]; + u32 RF2 = state->m_RF1[RFBand]; + u32 RF3 = state->m_RF1[RFBand]; + s32 RF_A1 = state->m_RF_A1[RFBand]; + s32 RF_B1 = state->m_RF_B1[RFBand]; + s32 RF_A2 = state->m_RF_A2[RFBand]; + s32 RF_B2 = state->m_RF_B2[RFBand]; + s32 Capprox = 0; + int TComp; + + state->m_Regs[EP3] &= ~0xE0; /* Power up */ + status = UpdateReg(state, EP3); + if (status < 0) + break; + + status = ThermometerRead(state, &TMValue_Current); + if (status < 0) + break; + + if (RF3 == 0 || Frequency < RF2) + Capprox = RF_A1 * ((s32)(Frequency) - (s32)(RF1)) + RF_B1 + Cprog_table; + else + Capprox = RF_A2 * ((s32)(Frequency) - (s32)(RF2)) + RF_B2 + Cprog_table; + + TComp = (int)(dCoverdT) * ((int)(TMValue_Current) - (int)(state->m_TMValue_RFCal))/1000; + + Capprox += TComp; + + if (Capprox < 0) + Capprox = 0; + else if (Capprox > 255) + Capprox = 255; + + + /* TODO Temperature compensation. There is defenitely a scale factor */ + /* missing in the datasheet, so leave it out for now. */ + state->m_Regs[EB14] = Capprox; + + status = UpdateReg(state, EB14); + if (status < 0) + break; + + } while (0); + return status; +} + +static int ChannelConfiguration(struct tda_state *state, + u32 Frequency, int Standard) +{ + + s32 IntermediateFrequency = m_StandardTable[Standard].m_IFFrequency; + int status = 0; + + u8 BP_Filter = 0; + u8 RF_Band = 0; + u8 GainTaper = 0; + u8 IR_Meas = 0; + + state->IF = IntermediateFrequency; + /* printk("tda18271c2dd: %s Freq = %d Standard = %d IF = %d\n", __func__, Frequency, Standard, IntermediateFrequency); */ + /* get values from tables */ + + if (!(SearchMap1(m_BP_Filter_Map, Frequency, &BP_Filter) && + SearchMap1(m_GainTaper_Map, Frequency, &GainTaper) && + SearchMap1(m_IR_Meas_Map, Frequency, &IR_Meas) && + SearchMap4(m_RF_Band_Map, Frequency, &RF_Band))) { + + printk(KERN_ERR "tda18271c2dd: %s SearchMap failed\n", __func__); + return -EINVAL; + } + + do { + state->m_Regs[EP3] = (state->m_Regs[EP3] & ~0x1F) | m_StandardTable[Standard].m_EP3_4_0; + state->m_Regs[EP3] &= ~0x04; /* switch RFAGC to high speed mode */ + + /* m_EP4 default for XToutOn, CAL_Mode (0) */ + state->m_Regs[EP4] = state->m_EP4 | ((Standard > HF_AnalogMax) ? state->m_IFLevelDigital : state->m_IFLevelAnalog); + /* state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDigital; */ + if (Standard <= HF_AnalogMax) + state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelAnalog; + else if (Standard <= HF_ATSC) + state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDVBT; + else if (Standard <= HF_DVBC) + state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDVBC; + else + state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDigital; + + if ((Standard == HF_FM_Radio) && state->m_bFMInput) + state->m_Regs[EP4] |= 80; + + state->m_Regs[MPD] &= ~0x80; + if (Standard > HF_AnalogMax) + state->m_Regs[MPD] |= 0x80; /* Add IF_notch for digital */ + + state->m_Regs[EB22] = m_StandardTable[Standard].m_EB22; + + /* Note: This is missing from flowchart in TDA18271 specification ( 1.5 MHz cutoff for FM ) */ + if (Standard == HF_FM_Radio) + state->m_Regs[EB23] |= 0x06; /* ForceLP_Fc2_En = 1, LPFc[2] = 1 */ + else + state->m_Regs[EB23] &= ~0x06; /* ForceLP_Fc2_En = 0, LPFc[2] = 0 */ + + status = UpdateRegs(state, EB22, EB23); + if (status < 0) + break; + + state->m_Regs[EP1] = (state->m_Regs[EP1] & ~0x07) | 0x40 | BP_Filter; /* Dis_Power_level = 1, Filter */ + state->m_Regs[EP5] = (state->m_Regs[EP5] & ~0x07) | IR_Meas; + state->m_Regs[EP2] = (RF_Band << 5) | GainTaper; + + state->m_Regs[EB1] = (state->m_Regs[EB1] & ~0x07) | + (state->m_bMaster ? 0x04 : 0x00); /* CALVCO_FortLOn = MS */ + /* AGC1_always_master = 0 */ + /* AGC_firstn = 0 */ + status = UpdateReg(state, EB1); + if (status < 0) + break; + + if (state->m_bMaster) { + status = CalcMainPLL(state, Frequency + IntermediateFrequency); + if (status < 0) + break; + status = UpdateRegs(state, TM, EP5); + if (status < 0) + break; + state->m_Regs[EB4] |= 0x20; /* LO_forceSrce = 1 */ + status = UpdateReg(state, EB4); + if (status < 0) + break; + msleep(1); + state->m_Regs[EB4] &= ~0x20; /* LO_forceSrce = 0 */ + status = UpdateReg(state, EB4); + if (status < 0) + break; + } else { + u8 PostDiv = 0; + u8 Div; + status = CalcCalPLL(state, Frequency + IntermediateFrequency); + if (status < 0) + break; + + SearchMap3(m_Cal_PLL_Map, Frequency + IntermediateFrequency, &PostDiv, &Div); + state->m_Regs[MPD] = (state->m_Regs[MPD] & ~0x7F) | (PostDiv & 0x77); + status = UpdateReg(state, MPD); + if (status < 0) + break; + status = UpdateRegs(state, TM, EP5); + if (status < 0) + break; + + state->m_Regs[EB7] |= 0x20; /* CAL_forceSrce = 1 */ + status = UpdateReg(state, EB7); + if (status < 0) + break; + msleep(1); + state->m_Regs[EB7] &= ~0x20; /* CAL_forceSrce = 0 */ + status = UpdateReg(state, EB7); + if (status < 0) + break; + } + msleep(20); + if (Standard != HF_FM_Radio) + state->m_Regs[EP3] |= 0x04; /* RFAGC to normal mode */ + status = UpdateReg(state, EP3); + if (status < 0) + break; + + } while (0); + return status; +} + +static int sleep(struct dvb_frontend *fe) +{ + struct tda_state *state = fe->tuner_priv; + + StandBy(state); + return 0; +} + +static int init(struct dvb_frontend *fe) +{ + return 0; +} + +static int release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +/* + * As defined on EN 300 429 Annex A and on ITU-T J.83 annex A, the DVB-C + * roll-off factor is 0.15. + * According with the specs, the amount of the needed bandwith is given by: + * Bw = Symbol_rate * (1 + 0.15) + * As such, the maximum symbol rate supported by 6 MHz is + * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds + *NOTE: For ITU-T J.83 Annex C, the roll-off factor is 0.13. So: + * max_symbol_rate = 6 MHz / 1.13 = 5309735 Baud + * That means that an adjustment is needed for Japan, + * but, as currently DRX-K is hardcoded to Annex A, let's stick + * with 0.15 roll-off factor. + */ +#define MAX_SYMBOL_RATE_6MHz 5217391 + +static int set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct tda_state *state = fe->tuner_priv; + int status = 0; + int Standard; + + state->m_Frequency = params->frequency; + + if (fe->ops.info.type == FE_OFDM) + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + Standard = HF_DVBT_6MHZ; + break; + case BANDWIDTH_7_MHZ: + Standard = HF_DVBT_7MHZ; + break; + default: + case BANDWIDTH_8_MHZ: + Standard = HF_DVBT_8MHZ; + break; + } + else if (fe->ops.info.type == FE_QAM) { + if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz) + Standard = HF_DVBC_6MHZ; + else + Standard = HF_DVBC_8MHZ; + } else + return -EINVAL; + do { + status = RFTrackingFiltersCorrection(state, params->frequency); + if (status < 0) + break; + status = ChannelConfiguration(state, params->frequency, Standard); + if (status < 0) + break; + + msleep(state->m_SettlingTime); /* Allow AGC's to settle down */ + } while (0); + return status; +} + +#if 0 +static int GetSignalStrength(s32 *pSignalStrength, u32 RFAgc, u32 IFAgc) +{ + if (IFAgc < 500) { + /* Scale this from 0 to 50000 */ + *pSignalStrength = IFAgc * 100; + } else { + /* Scale range 500-1500 to 50000-80000 */ + *pSignalStrength = 50000 + (IFAgc - 500) * 30; + } + + return 0; +} +#endif + +static int get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda_state *state = fe->tuner_priv; + + *frequency = state->IF; + return 0; +} + +static int get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + /* struct tda_state *state = fe->tuner_priv; */ + /* *bandwidth = priv->bandwidth; */ + return 0; +} + + +static struct dvb_tuner_ops tuner_ops = { + .info = { + .name = "NXP TDA18271C2D", + .frequency_min = 47125000, + .frequency_max = 865000000, + .frequency_step = 62500 + }, + .init = init, + .sleep = sleep, + .set_params = set_params, + .release = release, + .get_frequency = get_frequency, + .get_bandwidth = get_bandwidth, +}; + +struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 adr) +{ + struct tda_state *state; + + state = kzalloc(sizeof(struct tda_state), GFP_KERNEL); + if (!state) + return NULL; + + fe->tuner_priv = state; + state->adr = adr; + state->i2c = i2c; + memcpy(&fe->ops.tuner_ops, &tuner_ops, sizeof(struct dvb_tuner_ops)); + reset(state); + InitCal(state); + + return fe; +} +EXPORT_SYMBOL_GPL(tda18271c2dd_attach); + +MODULE_DESCRIPTION("TDA18271C2 driver"); +MODULE_AUTHOR("DD"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/tda18271c2dd.h b/drivers/media/dvb/frontends/tda18271c2dd.h new file mode 100644 index 0000000000000000000000000000000000000000..1389c74e12cee40efde49da9ac814914b12ba562 --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271c2dd.h @@ -0,0 +1,16 @@ +#ifndef _TDA18271C2DD_H_ +#define _TDA18271C2DD_H_ +#if defined(CONFIG_DVB_TDA18271C2DD) || (defined(CONFIG_DVB_TDA18271C2DD_MODULE) \ + && defined(MODULE)) +struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 adr); +#else +static inline struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 adr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff --git a/drivers/media/dvb/frontends/tda18271c2dd_maps.h b/drivers/media/dvb/frontends/tda18271c2dd_maps.h new file mode 100644 index 0000000000000000000000000000000000000000..b87661b9df14f714bb07e057f34388f91091288a --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271c2dd_maps.h @@ -0,0 +1,814 @@ +enum HF_S { + HF_None = 0, HF_B, HF_DK, HF_G, HF_I, HF_L, HF_L1, HF_MN, HF_FM_Radio, + HF_AnalogMax, HF_DVBT_6MHZ, HF_DVBT_7MHZ, HF_DVBT_8MHZ, + HF_DVBT, HF_ATSC, HF_DVBC_6MHZ, HF_DVBC_7MHZ, + HF_DVBC_8MHZ, HF_DVBC +}; + +struct SStandardParam m_StandardTable[] = { + { 0, 0, 0x00, 0x00 }, /* HF_None */ + { 6000000, 7000000, 0x1D, 0x2C }, /* HF_B, */ + { 6900000, 8000000, 0x1E, 0x2C }, /* HF_DK, */ + { 7100000, 8000000, 0x1E, 0x2C }, /* HF_G, */ + { 7250000, 8000000, 0x1E, 0x2C }, /* HF_I, */ + { 6900000, 8000000, 0x1E, 0x2C }, /* HF_L, */ + { 1250000, 8000000, 0x1E, 0x2C }, /* HF_L1, */ + { 5400000, 6000000, 0x1C, 0x2C }, /* HF_MN, */ + { 1250000, 500000, 0x18, 0x2C }, /* HF_FM_Radio, */ + { 0, 0, 0x00, 0x00 }, /* HF_AnalogMax (Unused) */ + { 3300000, 6000000, 0x1C, 0x58 }, /* HF_DVBT_6MHZ */ + { 3500000, 7000000, 0x1C, 0x37 }, /* HF_DVBT_7MHZ */ + { 4000000, 8000000, 0x1D, 0x37 }, /* HF_DVBT_8MHZ */ + { 0, 0, 0x00, 0x00 }, /* HF_DVBT (Unused) */ + { 5000000, 6000000, 0x1C, 0x37 }, /* HF_ATSC (center = 3.25 MHz) */ + { 4000000, 6000000, 0x1D, 0x58 }, /* HF_DVBC_6MHZ (Chicago) */ + { 4500000, 7000000, 0x1E, 0x37 }, /* HF_DVBC_7MHZ (not documented by NXP) */ + { 5000000, 8000000, 0x1F, 0x37 }, /* HF_DVBC_8MHZ */ + { 0, 0, 0x00, 0x00 }, /* HF_DVBC (Unused) */ +}; + +struct SMap m_BP_Filter_Map[] = { + { 62000000, 0x00 }, + { 84000000, 0x01 }, + { 100000000, 0x02 }, + { 140000000, 0x03 }, + { 170000000, 0x04 }, + { 180000000, 0x05 }, + { 865000000, 0x06 }, + { 0, 0x00 }, /* Table End */ +}; + +static struct SMapI m_RF_Cal_Map[] = { + { 41000000, 0x0F }, + { 43000000, 0x1C }, + { 45000000, 0x2F }, + { 46000000, 0x39 }, + { 47000000, 0x40 }, + { 47900000, 0x50 }, + { 49100000, 0x16 }, + { 50000000, 0x18 }, + { 51000000, 0x20 }, + { 53000000, 0x28 }, + { 55000000, 0x2B }, + { 56000000, 0x32 }, + { 57000000, 0x35 }, + { 58000000, 0x3E }, + { 59000000, 0x43 }, + { 60000000, 0x4E }, + { 61100000, 0x55 }, + { 63000000, 0x0F }, + { 64000000, 0x11 }, + { 65000000, 0x12 }, + { 66000000, 0x15 }, + { 67000000, 0x16 }, + { 68000000, 0x17 }, + { 70000000, 0x19 }, + { 71000000, 0x1C }, + { 72000000, 0x1D }, + { 73000000, 0x1F }, + { 74000000, 0x20 }, + { 75000000, 0x21 }, + { 76000000, 0x24 }, + { 77000000, 0x25 }, + { 78000000, 0x27 }, + { 80000000, 0x28 }, + { 81000000, 0x29 }, + { 82000000, 0x2D }, + { 83000000, 0x2E }, + { 84000000, 0x2F }, + { 85000000, 0x31 }, + { 86000000, 0x33 }, + { 87000000, 0x34 }, + { 88000000, 0x35 }, + { 89000000, 0x37 }, + { 90000000, 0x38 }, + { 91000000, 0x39 }, + { 93000000, 0x3C }, + { 94000000, 0x3E }, + { 95000000, 0x3F }, + { 96000000, 0x40 }, + { 97000000, 0x42 }, + { 99000000, 0x45 }, + { 100000000, 0x46 }, + { 102000000, 0x48 }, + { 103000000, 0x4A }, + { 105000000, 0x4D }, + { 106000000, 0x4E }, + { 107000000, 0x50 }, + { 108000000, 0x51 }, + { 110000000, 0x54 }, + { 111000000, 0x56 }, + { 112000000, 0x57 }, + { 113000000, 0x58 }, + { 114000000, 0x59 }, + { 115000000, 0x5C }, + { 116000000, 0x5D }, + { 117000000, 0x5F }, + { 119000000, 0x60 }, + { 120000000, 0x64 }, + { 121000000, 0x65 }, + { 122000000, 0x66 }, + { 123000000, 0x68 }, + { 124000000, 0x69 }, + { 125000000, 0x6C }, + { 126000000, 0x6D }, + { 127000000, 0x6E }, + { 128000000, 0x70 }, + { 129000000, 0x71 }, + { 130000000, 0x75 }, + { 131000000, 0x77 }, + { 132000000, 0x78 }, + { 133000000, 0x7B }, + { 134000000, 0x7E }, + { 135000000, 0x81 }, + { 136000000, 0x82 }, + { 137000000, 0x87 }, + { 138000000, 0x88 }, + { 139000000, 0x8D }, + { 140000000, 0x8E }, + { 141000000, 0x91 }, + { 142000000, 0x95 }, + { 143000000, 0x9A }, + { 144000000, 0x9D }, + { 145000000, 0xA1 }, + { 146000000, 0xA2 }, + { 147000000, 0xA4 }, + { 148000000, 0xA9 }, + { 149000000, 0xAE }, + { 150000000, 0xB0 }, + { 151000000, 0xB1 }, + { 152000000, 0xB7 }, + { 152600000, 0xBD }, + { 154000000, 0x20 }, + { 155000000, 0x22 }, + { 156000000, 0x24 }, + { 157000000, 0x25 }, + { 158000000, 0x27 }, + { 159000000, 0x29 }, + { 160000000, 0x2C }, + { 161000000, 0x2D }, + { 163000000, 0x2E }, + { 164000000, 0x2F }, + { 164700000, 0x30 }, + { 166000000, 0x11 }, + { 167000000, 0x12 }, + { 168000000, 0x13 }, + { 169000000, 0x14 }, + { 170000000, 0x15 }, + { 172000000, 0x16 }, + { 173000000, 0x17 }, + { 174000000, 0x18 }, + { 175000000, 0x1A }, + { 176000000, 0x1B }, + { 178000000, 0x1D }, + { 179000000, 0x1E }, + { 180000000, 0x1F }, + { 181000000, 0x20 }, + { 182000000, 0x21 }, + { 183000000, 0x22 }, + { 184000000, 0x24 }, + { 185000000, 0x25 }, + { 186000000, 0x26 }, + { 187000000, 0x27 }, + { 188000000, 0x29 }, + { 189000000, 0x2A }, + { 190000000, 0x2C }, + { 191000000, 0x2D }, + { 192000000, 0x2E }, + { 193000000, 0x2F }, + { 194000000, 0x30 }, + { 195000000, 0x33 }, + { 196000000, 0x35 }, + { 198000000, 0x36 }, + { 200000000, 0x38 }, + { 201000000, 0x3C }, + { 202000000, 0x3D }, + { 203500000, 0x3E }, + { 206000000, 0x0E }, + { 208000000, 0x0F }, + { 212000000, 0x10 }, + { 216000000, 0x11 }, + { 217000000, 0x12 }, + { 218000000, 0x13 }, + { 220000000, 0x14 }, + { 222000000, 0x15 }, + { 225000000, 0x16 }, + { 228000000, 0x17 }, + { 231000000, 0x18 }, + { 234000000, 0x19 }, + { 235000000, 0x1A }, + { 236000000, 0x1B }, + { 237000000, 0x1C }, + { 240000000, 0x1D }, + { 242000000, 0x1E }, + { 244000000, 0x1F }, + { 247000000, 0x20 }, + { 249000000, 0x21 }, + { 252000000, 0x22 }, + { 253000000, 0x23 }, + { 254000000, 0x24 }, + { 256000000, 0x25 }, + { 259000000, 0x26 }, + { 262000000, 0x27 }, + { 264000000, 0x28 }, + { 267000000, 0x29 }, + { 269000000, 0x2A }, + { 271000000, 0x2B }, + { 273000000, 0x2C }, + { 275000000, 0x2D }, + { 277000000, 0x2E }, + { 279000000, 0x2F }, + { 282000000, 0x30 }, + { 284000000, 0x31 }, + { 286000000, 0x32 }, + { 287000000, 0x33 }, + { 290000000, 0x34 }, + { 293000000, 0x35 }, + { 295000000, 0x36 }, + { 297000000, 0x37 }, + { 300000000, 0x38 }, + { 303000000, 0x39 }, + { 305000000, 0x3A }, + { 306000000, 0x3B }, + { 307000000, 0x3C }, + { 310000000, 0x3D }, + { 312000000, 0x3E }, + { 315000000, 0x3F }, + { 318000000, 0x40 }, + { 320000000, 0x41 }, + { 323000000, 0x42 }, + { 324000000, 0x43 }, + { 325000000, 0x44 }, + { 327000000, 0x45 }, + { 331000000, 0x46 }, + { 334000000, 0x47 }, + { 337000000, 0x48 }, + { 339000000, 0x49 }, + { 340000000, 0x4A }, + { 341000000, 0x4B }, + { 343000000, 0x4C }, + { 345000000, 0x4D }, + { 349000000, 0x4E }, + { 352000000, 0x4F }, + { 353000000, 0x50 }, + { 355000000, 0x51 }, + { 357000000, 0x52 }, + { 359000000, 0x53 }, + { 361000000, 0x54 }, + { 362000000, 0x55 }, + { 364000000, 0x56 }, + { 368000000, 0x57 }, + { 370000000, 0x58 }, + { 372000000, 0x59 }, + { 375000000, 0x5A }, + { 376000000, 0x5B }, + { 377000000, 0x5C }, + { 379000000, 0x5D }, + { 382000000, 0x5E }, + { 384000000, 0x5F }, + { 385000000, 0x60 }, + { 386000000, 0x61 }, + { 388000000, 0x62 }, + { 390000000, 0x63 }, + { 393000000, 0x64 }, + { 394000000, 0x65 }, + { 396000000, 0x66 }, + { 397000000, 0x67 }, + { 398000000, 0x68 }, + { 400000000, 0x69 }, + { 402000000, 0x6A }, + { 403000000, 0x6B }, + { 407000000, 0x6C }, + { 408000000, 0x6D }, + { 409000000, 0x6E }, + { 410000000, 0x6F }, + { 411000000, 0x70 }, + { 412000000, 0x71 }, + { 413000000, 0x72 }, + { 414000000, 0x73 }, + { 417000000, 0x74 }, + { 418000000, 0x75 }, + { 420000000, 0x76 }, + { 422000000, 0x77 }, + { 423000000, 0x78 }, + { 424000000, 0x79 }, + { 427000000, 0x7A }, + { 428000000, 0x7B }, + { 429000000, 0x7D }, + { 432000000, 0x7F }, + { 434000000, 0x80 }, + { 435000000, 0x81 }, + { 436000000, 0x83 }, + { 437000000, 0x84 }, + { 438000000, 0x85 }, + { 439000000, 0x86 }, + { 440000000, 0x87 }, + { 441000000, 0x88 }, + { 442000000, 0x89 }, + { 445000000, 0x8A }, + { 446000000, 0x8B }, + { 447000000, 0x8C }, + { 448000000, 0x8E }, + { 449000000, 0x8F }, + { 450000000, 0x90 }, + { 452000000, 0x91 }, + { 453000000, 0x93 }, + { 454000000, 0x94 }, + { 456000000, 0x96 }, + { 457800000, 0x98 }, + { 461000000, 0x11 }, + { 468000000, 0x12 }, + { 472000000, 0x13 }, + { 473000000, 0x14 }, + { 474000000, 0x15 }, + { 481000000, 0x16 }, + { 486000000, 0x17 }, + { 491000000, 0x18 }, + { 498000000, 0x19 }, + { 499000000, 0x1A }, + { 501000000, 0x1B }, + { 506000000, 0x1C }, + { 511000000, 0x1D }, + { 516000000, 0x1E }, + { 520000000, 0x1F }, + { 521000000, 0x20 }, + { 525000000, 0x21 }, + { 529000000, 0x22 }, + { 533000000, 0x23 }, + { 539000000, 0x24 }, + { 541000000, 0x25 }, + { 547000000, 0x26 }, + { 549000000, 0x27 }, + { 551000000, 0x28 }, + { 556000000, 0x29 }, + { 561000000, 0x2A }, + { 563000000, 0x2B }, + { 565000000, 0x2C }, + { 569000000, 0x2D }, + { 571000000, 0x2E }, + { 577000000, 0x2F }, + { 580000000, 0x30 }, + { 582000000, 0x31 }, + { 584000000, 0x32 }, + { 588000000, 0x33 }, + { 591000000, 0x34 }, + { 596000000, 0x35 }, + { 598000000, 0x36 }, + { 603000000, 0x37 }, + { 604000000, 0x38 }, + { 606000000, 0x39 }, + { 612000000, 0x3A }, + { 615000000, 0x3B }, + { 617000000, 0x3C }, + { 621000000, 0x3D }, + { 622000000, 0x3E }, + { 625000000, 0x3F }, + { 632000000, 0x40 }, + { 633000000, 0x41 }, + { 634000000, 0x42 }, + { 642000000, 0x43 }, + { 643000000, 0x44 }, + { 647000000, 0x45 }, + { 650000000, 0x46 }, + { 652000000, 0x47 }, + { 657000000, 0x48 }, + { 661000000, 0x49 }, + { 662000000, 0x4A }, + { 665000000, 0x4B }, + { 667000000, 0x4C }, + { 670000000, 0x4D }, + { 673000000, 0x4E }, + { 676000000, 0x4F }, + { 677000000, 0x50 }, + { 681000000, 0x51 }, + { 683000000, 0x52 }, + { 686000000, 0x53 }, + { 688000000, 0x54 }, + { 689000000, 0x55 }, + { 691000000, 0x56 }, + { 695000000, 0x57 }, + { 698000000, 0x58 }, + { 703000000, 0x59 }, + { 704000000, 0x5A }, + { 705000000, 0x5B }, + { 707000000, 0x5C }, + { 710000000, 0x5D }, + { 712000000, 0x5E }, + { 717000000, 0x5F }, + { 718000000, 0x60 }, + { 721000000, 0x61 }, + { 722000000, 0x62 }, + { 723000000, 0x63 }, + { 725000000, 0x64 }, + { 727000000, 0x65 }, + { 730000000, 0x66 }, + { 732000000, 0x67 }, + { 735000000, 0x68 }, + { 740000000, 0x69 }, + { 741000000, 0x6A }, + { 742000000, 0x6B }, + { 743000000, 0x6C }, + { 745000000, 0x6D }, + { 747000000, 0x6E }, + { 748000000, 0x6F }, + { 750000000, 0x70 }, + { 752000000, 0x71 }, + { 754000000, 0x72 }, + { 757000000, 0x73 }, + { 758000000, 0x74 }, + { 760000000, 0x75 }, + { 763000000, 0x76 }, + { 764000000, 0x77 }, + { 766000000, 0x78 }, + { 767000000, 0x79 }, + { 768000000, 0x7A }, + { 773000000, 0x7B }, + { 774000000, 0x7C }, + { 776000000, 0x7D }, + { 777000000, 0x7E }, + { 778000000, 0x7F }, + { 779000000, 0x80 }, + { 781000000, 0x81 }, + { 783000000, 0x82 }, + { 784000000, 0x83 }, + { 785000000, 0x84 }, + { 786000000, 0x85 }, + { 793000000, 0x86 }, + { 794000000, 0x87 }, + { 795000000, 0x88 }, + { 797000000, 0x89 }, + { 799000000, 0x8A }, + { 801000000, 0x8B }, + { 802000000, 0x8C }, + { 803000000, 0x8D }, + { 804000000, 0x8E }, + { 810000000, 0x90 }, + { 811000000, 0x91 }, + { 812000000, 0x92 }, + { 814000000, 0x93 }, + { 816000000, 0x94 }, + { 817000000, 0x96 }, + { 818000000, 0x97 }, + { 820000000, 0x98 }, + { 821000000, 0x99 }, + { 822000000, 0x9A }, + { 828000000, 0x9B }, + { 829000000, 0x9D }, + { 830000000, 0x9F }, + { 831000000, 0xA0 }, + { 833000000, 0xA1 }, + { 835000000, 0xA2 }, + { 836000000, 0xA3 }, + { 837000000, 0xA4 }, + { 838000000, 0xA6 }, + { 840000000, 0xA8 }, + { 842000000, 0xA9 }, + { 845000000, 0xAA }, + { 846000000, 0xAB }, + { 847000000, 0xAD }, + { 848000000, 0xAE }, + { 852000000, 0xAF }, + { 853000000, 0xB0 }, + { 858000000, 0xB1 }, + { 860000000, 0xB2 }, + { 861000000, 0xB3 }, + { 862000000, 0xB4 }, + { 863000000, 0xB6 }, + { 864000000, 0xB8 }, + { 865000000, 0xB9 }, + { 0, 0x00 }, /* Table End */ +}; + + +static struct SMap2 m_KM_Map[] = { + { 47900000, 3, 2 }, + { 61100000, 3, 1 }, + { 350000000, 3, 0 }, + { 720000000, 2, 1 }, + { 865000000, 3, 3 }, + { 0, 0x00 }, /* Table End */ +}; + +static struct SMap2 m_Main_PLL_Map[] = { + { 33125000, 0x57, 0xF0 }, + { 35500000, 0x56, 0xE0 }, + { 38188000, 0x55, 0xD0 }, + { 41375000, 0x54, 0xC0 }, + { 45125000, 0x53, 0xB0 }, + { 49688000, 0x52, 0xA0 }, + { 55188000, 0x51, 0x90 }, + { 62125000, 0x50, 0x80 }, + { 66250000, 0x47, 0x78 }, + { 71000000, 0x46, 0x70 }, + { 76375000, 0x45, 0x68 }, + { 82750000, 0x44, 0x60 }, + { 90250000, 0x43, 0x58 }, + { 99375000, 0x42, 0x50 }, + { 110375000, 0x41, 0x48 }, + { 124250000, 0x40, 0x40 }, + { 132500000, 0x37, 0x3C }, + { 142000000, 0x36, 0x38 }, + { 152750000, 0x35, 0x34 }, + { 165500000, 0x34, 0x30 }, + { 180500000, 0x33, 0x2C }, + { 198750000, 0x32, 0x28 }, + { 220750000, 0x31, 0x24 }, + { 248500000, 0x30, 0x20 }, + { 265000000, 0x27, 0x1E }, + { 284000000, 0x26, 0x1C }, + { 305500000, 0x25, 0x1A }, + { 331000000, 0x24, 0x18 }, + { 361000000, 0x23, 0x16 }, + { 397500000, 0x22, 0x14 }, + { 441500000, 0x21, 0x12 }, + { 497000000, 0x20, 0x10 }, + { 530000000, 0x17, 0x0F }, + { 568000000, 0x16, 0x0E }, + { 611000000, 0x15, 0x0D }, + { 662000000, 0x14, 0x0C }, + { 722000000, 0x13, 0x0B }, + { 795000000, 0x12, 0x0A }, + { 883000000, 0x11, 0x09 }, + { 994000000, 0x10, 0x08 }, + { 0, 0x00, 0x00 }, /* Table End */ +}; + +static struct SMap2 m_Cal_PLL_Map[] = { + { 33813000, 0xDD, 0xD0 }, + { 36625000, 0xDC, 0xC0 }, + { 39938000, 0xDB, 0xB0 }, + { 43938000, 0xDA, 0xA0 }, + { 48813000, 0xD9, 0x90 }, + { 54938000, 0xD8, 0x80 }, + { 62813000, 0xD3, 0x70 }, + { 67625000, 0xCD, 0x68 }, + { 73250000, 0xCC, 0x60 }, + { 79875000, 0xCB, 0x58 }, + { 87875000, 0xCA, 0x50 }, + { 97625000, 0xC9, 0x48 }, + { 109875000, 0xC8, 0x40 }, + { 125625000, 0xC3, 0x38 }, + { 135250000, 0xBD, 0x34 }, + { 146500000, 0xBC, 0x30 }, + { 159750000, 0xBB, 0x2C }, + { 175750000, 0xBA, 0x28 }, + { 195250000, 0xB9, 0x24 }, + { 219750000, 0xB8, 0x20 }, + { 251250000, 0xB3, 0x1C }, + { 270500000, 0xAD, 0x1A }, + { 293000000, 0xAC, 0x18 }, + { 319500000, 0xAB, 0x16 }, + { 351500000, 0xAA, 0x14 }, + { 390500000, 0xA9, 0x12 }, + { 439500000, 0xA8, 0x10 }, + { 502500000, 0xA3, 0x0E }, + { 541000000, 0x9D, 0x0D }, + { 586000000, 0x9C, 0x0C }, + { 639000000, 0x9B, 0x0B }, + { 703000000, 0x9A, 0x0A }, + { 781000000, 0x99, 0x09 }, + { 879000000, 0x98, 0x08 }, + { 0, 0x00, 0x00 }, /* Table End */ +}; + +static struct SMap m_GainTaper_Map[] = { + { 45400000, 0x1F }, + { 45800000, 0x1E }, + { 46200000, 0x1D }, + { 46700000, 0x1C }, + { 47100000, 0x1B }, + { 47500000, 0x1A }, + { 47900000, 0x19 }, + { 49600000, 0x17 }, + { 51200000, 0x16 }, + { 52900000, 0x15 }, + { 54500000, 0x14 }, + { 56200000, 0x13 }, + { 57800000, 0x12 }, + { 59500000, 0x11 }, + { 61100000, 0x10 }, + { 67600000, 0x0D }, + { 74200000, 0x0C }, + { 80700000, 0x0B }, + { 87200000, 0x0A }, + { 93800000, 0x09 }, + { 100300000, 0x08 }, + { 106900000, 0x07 }, + { 113400000, 0x06 }, + { 119900000, 0x05 }, + { 126500000, 0x04 }, + { 133000000, 0x03 }, + { 139500000, 0x02 }, + { 146100000, 0x01 }, + { 152600000, 0x00 }, + { 154300000, 0x1F }, + { 156100000, 0x1E }, + { 157800000, 0x1D }, + { 159500000, 0x1C }, + { 161200000, 0x1B }, + { 163000000, 0x1A }, + { 164700000, 0x19 }, + { 170200000, 0x17 }, + { 175800000, 0x16 }, + { 181300000, 0x15 }, + { 186900000, 0x14 }, + { 192400000, 0x13 }, + { 198000000, 0x12 }, + { 203500000, 0x11 }, + { 216200000, 0x14 }, + { 228900000, 0x13 }, + { 241600000, 0x12 }, + { 254400000, 0x11 }, + { 267100000, 0x10 }, + { 279800000, 0x0F }, + { 292500000, 0x0E }, + { 305200000, 0x0D }, + { 317900000, 0x0C }, + { 330700000, 0x0B }, + { 343400000, 0x0A }, + { 356100000, 0x09 }, + { 368800000, 0x08 }, + { 381500000, 0x07 }, + { 394200000, 0x06 }, + { 406900000, 0x05 }, + { 419700000, 0x04 }, + { 432400000, 0x03 }, + { 445100000, 0x02 }, + { 457800000, 0x01 }, + { 476300000, 0x19 }, + { 494800000, 0x18 }, + { 513300000, 0x17 }, + { 531800000, 0x16 }, + { 550300000, 0x15 }, + { 568900000, 0x14 }, + { 587400000, 0x13 }, + { 605900000, 0x12 }, + { 624400000, 0x11 }, + { 642900000, 0x10 }, + { 661400000, 0x0F }, + { 679900000, 0x0E }, + { 698400000, 0x0D }, + { 716900000, 0x0C }, + { 735400000, 0x0B }, + { 753900000, 0x0A }, + { 772500000, 0x09 }, + { 791000000, 0x08 }, + { 809500000, 0x07 }, + { 828000000, 0x06 }, + { 846500000, 0x05 }, + { 865000000, 0x04 }, + { 0, 0x00 }, /* Table End */ +}; + +static struct SMap m_RF_Cal_DC_Over_DT_Map[] = { + { 47900000, 0x00 }, + { 55000000, 0x00 }, + { 61100000, 0x0A }, + { 64000000, 0x0A }, + { 82000000, 0x14 }, + { 84000000, 0x19 }, + { 119000000, 0x1C }, + { 124000000, 0x20 }, + { 129000000, 0x2A }, + { 134000000, 0x32 }, + { 139000000, 0x39 }, + { 144000000, 0x3E }, + { 149000000, 0x3F }, + { 152600000, 0x40 }, + { 154000000, 0x40 }, + { 164700000, 0x41 }, + { 203500000, 0x32 }, + { 353000000, 0x19 }, + { 356000000, 0x1A }, + { 359000000, 0x1B }, + { 363000000, 0x1C }, + { 366000000, 0x1D }, + { 369000000, 0x1E }, + { 373000000, 0x1F }, + { 376000000, 0x20 }, + { 379000000, 0x21 }, + { 383000000, 0x22 }, + { 386000000, 0x23 }, + { 389000000, 0x24 }, + { 393000000, 0x25 }, + { 396000000, 0x26 }, + { 399000000, 0x27 }, + { 402000000, 0x28 }, + { 404000000, 0x29 }, + { 407000000, 0x2A }, + { 409000000, 0x2B }, + { 412000000, 0x2C }, + { 414000000, 0x2D }, + { 417000000, 0x2E }, + { 419000000, 0x2F }, + { 422000000, 0x30 }, + { 424000000, 0x31 }, + { 427000000, 0x32 }, + { 429000000, 0x33 }, + { 432000000, 0x34 }, + { 434000000, 0x35 }, + { 437000000, 0x36 }, + { 439000000, 0x37 }, + { 442000000, 0x38 }, + { 444000000, 0x39 }, + { 447000000, 0x3A }, + { 449000000, 0x3B }, + { 457800000, 0x3C }, + { 465000000, 0x0F }, + { 477000000, 0x12 }, + { 483000000, 0x14 }, + { 502000000, 0x19 }, + { 508000000, 0x1B }, + { 519000000, 0x1C }, + { 522000000, 0x1D }, + { 524000000, 0x1E }, + { 534000000, 0x1F }, + { 549000000, 0x20 }, + { 554000000, 0x22 }, + { 584000000, 0x24 }, + { 589000000, 0x26 }, + { 658000000, 0x27 }, + { 664000000, 0x2C }, + { 669000000, 0x2D }, + { 699000000, 0x2E }, + { 704000000, 0x30 }, + { 709000000, 0x31 }, + { 714000000, 0x32 }, + { 724000000, 0x33 }, + { 729000000, 0x36 }, + { 739000000, 0x38 }, + { 744000000, 0x39 }, + { 749000000, 0x3B }, + { 754000000, 0x3C }, + { 759000000, 0x3D }, + { 764000000, 0x3E }, + { 769000000, 0x3F }, + { 774000000, 0x40 }, + { 779000000, 0x41 }, + { 784000000, 0x43 }, + { 789000000, 0x46 }, + { 794000000, 0x48 }, + { 799000000, 0x4B }, + { 804000000, 0x4F }, + { 809000000, 0x54 }, + { 814000000, 0x59 }, + { 819000000, 0x5D }, + { 824000000, 0x61 }, + { 829000000, 0x68 }, + { 834000000, 0x6E }, + { 839000000, 0x75 }, + { 844000000, 0x7E }, + { 849000000, 0x82 }, + { 854000000, 0x84 }, + { 859000000, 0x8F }, + { 865000000, 0x9A }, + { 0, 0x00 }, /* Table End */ +}; + + +static struct SMap m_IR_Meas_Map[] = { + { 200000000, 0x05 }, + { 400000000, 0x06 }, + { 865000000, 0x07 }, + { 0, 0x00 }, /* Table End */ +}; + +static struct SMap2 m_CID_Target_Map[] = { + { 46000000, 0x04, 18 }, + { 52200000, 0x0A, 15 }, + { 70100000, 0x01, 40 }, + { 136800000, 0x18, 40 }, + { 156700000, 0x18, 40 }, + { 186250000, 0x0A, 40 }, + { 230000000, 0x0A, 40 }, + { 345000000, 0x18, 40 }, + { 426000000, 0x0E, 40 }, + { 489500000, 0x1E, 40 }, + { 697500000, 0x32, 40 }, + { 842000000, 0x3A, 40 }, + { 0, 0x00, 0 }, /* Table End */ +}; + +static struct SRFBandMap m_RF_Band_Map[7] = { + { 47900000, 46000000, 0, 0}, + { 61100000, 52200000, 0, 0}, + { 152600000, 70100000, 136800000, 0}, + { 164700000, 156700000, 0, 0}, + { 203500000, 186250000, 0, 0}, + { 457800000, 230000000, 345000000, 426000000}, + { 865000000, 489500000, 697500000, 842000000}, +}; + +u8 m_Thermometer_Map_1[16] = { + 60, 62, 66, 64, + 74, 72, 68, 70, + 90, 88, 84, 86, + 76, 78, 82, 80, +}; + +u8 m_Thermometer_Map_2[16] = { + 92, 94, 98, 96, + 106, 104, 100, 102, + 122, 120, 116, 118, + 108, 110, 114, 112, +}; diff --git a/drivers/media/dvb/ngene/Kconfig b/drivers/media/dvb/ngene/Kconfig index cec242b7c00d18e535fddca037f5f56ddc3762a3..64c84702ba5cf66be59300f89bfa1cc83c98fb5c 100644 --- a/drivers/media/dvb/ngene/Kconfig +++ b/drivers/media/dvb/ngene/Kconfig @@ -5,6 +5,8 @@ config DVB_NGENE select DVB_STV6110x if !DVB_FE_CUSTOMISE select DVB_STV090x if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_DRXK if !DVB_FE_CUSTOMISE + select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE ---help--- Support for Micronas PCI express cards with nGene bridge. diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c index fcf4be901ec8675bed8d9346b3e4ca22e73264fa..056419228363f8344eefbab82ef8b05eb24feace 100644 --- a/drivers/media/dvb/ngene/ngene-cards.c +++ b/drivers/media/dvb/ngene/ngene-cards.c @@ -40,6 +40,8 @@ #include "lnbh24.h" #include "lgdt330x.h" #include "mt2131.h" +#include "tda18271c2dd.h" +#include "drxk.h" /****************************************************************************/ @@ -83,6 +85,49 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) } +static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct ngene_channel *chan = fe->sec_priv; + int status; + + if (enable) { + down(&chan->dev->pll_mutex); + status = chan->gate_ctrl(fe, 1); + } else { + status = chan->gate_ctrl(fe, 0); + up(&chan->dev->pll_mutex); + } + return status; +} + +static int tuner_attach_tda18271(struct ngene_channel *chan) +{ + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + + i2c = &chan->dev->channel[0].i2c_adapter; + if (chan->fe->ops.i2c_gate_ctrl) + chan->fe->ops.i2c_gate_ctrl(chan->fe, 1); + fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60); + if (chan->fe->ops.i2c_gate_ctrl) + chan->fe->ops.i2c_gate_ctrl(chan->fe, 0); + if (!fe) { + printk(KERN_ERR "No TDA18271 found!\n"); + return -ENODEV; + } + + return 0; +} + +static int tuner_attach_probe(struct ngene_channel *chan) +{ + if (chan->demod_type == 0) + return tuner_attach_stv6110(chan); + if (chan->demod_type == 1) + return tuner_attach_tda18271(chan); + return -EINVAL; +} + static int demod_attach_stv0900(struct ngene_channel *chan) { struct i2c_adapter *i2c; @@ -130,6 +175,60 @@ static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock) up(&chan->dev->pll_mutex); } +static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) +{ + struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1 } }; + return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; +} + +static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, + u16 reg, u8 *val) +{ + u8 msg[2] = {reg>>8, reg&0xff}; + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = msg, .len = 2}, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1} }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int port_has_stv0900(struct i2c_adapter *i2c, int port) +{ + u8 val; + if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0) + return 0; + return 1; +} + +static int port_has_drxk(struct i2c_adapter *i2c, int port) +{ + u8 val; + + if (i2c_read(i2c, 0x29+port, &val) < 0) + return 0; + return 1; +} + +static int demod_attach_drxk(struct ngene_channel *chan, + struct i2c_adapter *i2c) +{ + struct drxk_config config; + + memset(&config, 0, sizeof(config)); + config.adr = 0x29 + (chan->number ^ 2); + + chan->fe = dvb_attach(drxk_attach, &config, i2c, &chan->fe2); + if (!chan->fe) { + printk(KERN_ERR "No DRXK found!\n"); + return -ENODEV; + } + chan->fe->sec_priv = chan; + chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl; + chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; + return 0; +} + static int cineS2_probe(struct ngene_channel *chan) { struct i2c_adapter *i2c; @@ -144,43 +243,42 @@ static int cineS2_probe(struct ngene_channel *chan) else i2c = &chan->dev->channel[1].i2c_adapter; - fe_conf = chan->dev->card_info->fe_config[chan->number]; - i2c_msg.addr = fe_conf->address; - - /* probe demod */ - i2c_msg.len = 2; - buf[0] = 0xf1; - buf[1] = 0x00; - rc = i2c_transfer(i2c, &i2c_msg, 1); - if (rc != 1) - return -ENODEV; - - /* demod found, attach it */ - rc = demod_attach_stv0900(chan); - if (rc < 0 || chan->number < 2) - return rc; - - /* demod #2: reprogram outputs DPN1 & DPN2 */ - i2c_msg.len = 3; - buf[0] = 0xf1; - switch (chan->number) { - case 2: - buf[1] = 0x5c; - buf[2] = 0xc2; - break; - case 3: - buf[1] = 0x61; - buf[2] = 0xcc; - break; - default: + if (port_has_stv0900(i2c, chan->number)) { + chan->demod_type = 0; + fe_conf = chan->dev->card_info->fe_config[chan->number]; + /* demod found, attach it */ + rc = demod_attach_stv0900(chan); + if (rc < 0 || chan->number < 2) + return rc; + + /* demod #2: reprogram outputs DPN1 & DPN2 */ + i2c_msg.addr = fe_conf->address; + i2c_msg.len = 3; + buf[0] = 0xf1; + switch (chan->number) { + case 2: + buf[1] = 0x5c; + buf[2] = 0xc2; + break; + case 3: + buf[1] = 0x61; + buf[2] = 0xcc; + break; + default: + return -ENODEV; + } + rc = i2c_transfer(i2c, &i2c_msg, 1); + if (rc != 1) { + printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n"); + return -EIO; + } + } else if (port_has_drxk(i2c, chan->number^2)) { + chan->demod_type = 1; + demod_attach_drxk(chan, i2c); + } else { + printk(KERN_ERR "No demod found on chan %d\n", chan->number); return -ENODEV; } - rc = i2c_transfer(i2c, &i2c_msg, 1); - if (rc != 1) { - printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n"); - return -EIO; - } - return 0; } @@ -306,7 +404,7 @@ static struct ngene_info ngene_info_satixS2v2 = { .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSOUT}, .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, - .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe}, .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, .lnb = {0x0a, 0x08, 0x0b, 0x09}, @@ -321,7 +419,7 @@ static struct ngene_info ngene_info_cineS2v5 = { .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSOUT}, .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, - .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe}, .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, .lnb = {0x0a, 0x08, 0x0b, 0x09}, @@ -331,13 +429,13 @@ static struct ngene_info ngene_info_cineS2v5 = { }; -static struct ngene_info ngene_info_duoFlexS2 = { +static struct ngene_info ngene_info_duoFlex = { .type = NGENE_SIDEWINDER, - .name = "Digital Devices DuoFlex S2 miniPCIe", + .name = "Digital Devices DuoFlex PCIe or miniPCIe", .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSOUT}, .demod_attach = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe}, - .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110}, + .tuner_attach = {tuner_attach_probe, tuner_attach_probe, tuner_attach_probe, tuner_attach_probe}, .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, .lnb = {0x0a, 0x08, 0x0b, 0x09}, @@ -385,8 +483,8 @@ static const struct pci_device_id ngene_id_tbl[] __devinitdata = { NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2), NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2), NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5), - NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlexS2), - NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlexS2), + NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlex), + NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex), NGENE_ID(0x1461, 0x062e, ngene_info_m780), {0} }; diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index 6927c726ce35b4ec1c8139eb838e7822dded28da..f129a9303f80a364f0956fb17033169f8a11a659 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -41,7 +41,7 @@ #include "ngene.h" -static int one_adapter = 1; +static int one_adapter; module_param(one_adapter, int, 0444); MODULE_PARM_DESC(one_adapter, "Use only one adapter."); @@ -461,7 +461,7 @@ static u8 TSFeatureDecoderSetup[8 * 5] = { 0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, 0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXH */ 0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXHser */ - 0x72, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */ + 0x72, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */ 0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */ }; @@ -507,7 +507,7 @@ void FillTSBuffer(void *Buffer, int Length, u32 Flags) { u32 *ptr = Buffer; - memset(Buffer, 0xff, Length); + memset(Buffer, TS_FILLER, Length); while (Length > 0) { if (Flags & DF_SWAP32) *ptr = 0x471FFF10; @@ -1443,6 +1443,9 @@ static void release_channel(struct ngene_channel *chan) chan->ci_dev = NULL; } + if (chan->fe2) + dvb_unregister_frontend(chan->fe2); + if (chan->fe) { dvb_unregister_frontend(chan->fe); dvb_frontend_detach(chan->fe); @@ -1534,6 +1537,14 @@ static int init_channel(struct ngene_channel *chan) goto err; chan->has_demux = true; } + if (chan->fe2) { + if (dvb_register_frontend(adapter, chan->fe2) < 0) + goto err; + chan->fe2->tuner_priv = chan->fe->tuner_priv; + memcpy(&chan->fe2->ops.tuner_ops, + &chan->fe->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); + } if (chan->has_demux) { ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", @@ -1571,11 +1582,18 @@ static int init_channels(struct ngene *dev) return 0; } +static struct cxd2099_cfg cxd_cfg = { + .bitrate = 62000, + .adr = 0x40, + .polarity = 0, + .clock_mode = 0, +}; + static void cxd_attach(struct ngene *dev) { struct ngene_ci *ci = &dev->ci; - ci->en = cxd2099_attach(0x40, dev, &dev->channel[0].i2c_adapter); + ci->en = cxd2099_attach(&cxd_cfg, dev, &dev->channel[0].i2c_adapter); ci->dev = dev; return; } diff --git a/drivers/media/dvb/ngene/ngene-dvb.c b/drivers/media/dvb/ngene/ngene-dvb.c index 0b4943233166e67824ff39cbebb5a859fe4b1497..fcb16a615aab002768f80b3e7d6c5cf66ac5f123 100644 --- a/drivers/media/dvb/ngene/ngene-dvb.c +++ b/drivers/media/dvb/ngene/ngene-dvb.c @@ -118,6 +118,16 @@ static void swap_buffer(u32 *p, u32 len) } } +/* start of filler packet */ +static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER }; + +/* #define DEBUG_CI_XFER */ +#ifdef DEBUG_CI_XFER +static u32 ok; +static u32 overflow; +static u32 stripped; +#endif + void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) { struct ngene_channel *chan = priv; @@ -126,21 +136,41 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) if (flags & DF_SWAP32) swap_buffer(buf, len); + if (dev->ci.en && chan->number == 2) { - if (dvb_ringbuffer_free(&dev->tsin_rbuf) > len) { - dvb_ringbuffer_write(&dev->tsin_rbuf, buf, len); - wake_up_interruptible(&dev->tsin_rbuf.queue); + while (len >= 188) { + if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) { + if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) { + dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188); + wake_up(&dev->tsin_rbuf.queue); +#ifdef DEBUG_CI_XFER + ok++; +#endif + } +#ifdef DEBUG_CI_XFER + else + overflow++; +#endif + } +#ifdef DEBUG_CI_XFER + else + stripped++; + + if (ok % 100 == 0 && overflow) + printk(KERN_WARNING "%s: ok %u overflow %u dropped %u\n", __func__, ok, overflow, stripped); +#endif + buf += 188; + len -= 188; } - return 0; + return NULL; } - if (chan->users > 0) { + + if (chan->users > 0) dvb_dmx_swfilter(&chan->demux, buf, len); - } + return NULL; } -u8 fill_ts[188] = { 0x47, 0x1f, 0xff, 0x10 }; - void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) { struct ngene_channel *chan = priv; diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h index 40fce9e3ae66323435ec36cfb75d1049361a85f7..5443dc0caea50e2067a68c5df66d6563d79f7f58 100644 --- a/drivers/media/dvb/ngene/ngene.h +++ b/drivers/media/dvb/ngene/ngene.h @@ -641,8 +641,11 @@ struct ngene_channel { int mode; bool has_adapter; bool has_demux; + int demod_type; + int (*gate_ctrl)(struct dvb_frontend *, int); struct dvb_frontend *fe; + struct dvb_frontend *fe2; struct dmxdev dmxdev; struct dvb_demux demux; struct dvb_net dvbnet; @@ -786,6 +789,8 @@ struct ngene { u8 uart_rbuf[UART_RBUF_LEN]; int uart_rp, uart_wp; +#define TS_FILLER 0x6f + u8 *tsout_buf; #define TSOUT_BUF_SIZE (512*188*8) struct dvb_ringbuffer tsout_rbuf; @@ -852,7 +857,7 @@ struct ngene_info { }; #ifdef NGENE_V4L -struct ngene_format{ +struct ngene_format { char *name; int fourcc; /* video4linux 2 */ int btformat; /* BT848_COLOR_FMT_* */ diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c index 78765ed280631126abdabca42035eff8fe95dcc5..7331e8450d1a7d96caa64b2ba88e3d13be622b6f 100644 --- a/drivers/media/dvb/siano/smscoreapi.c +++ b/drivers/media/dvb/siano/smscoreapi.c @@ -1147,7 +1147,7 @@ static int smscore_validate_client(struct smscore_device_t *coredev, if (!client) { sms_err("bad parameter."); - return -EFAULT; + return -EINVAL; } registered_client = smscore_find_client(coredev, data_type, id); if (registered_client == client) diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h index 8ecadecaa9d0d9aa7de49612a4e7c0845162a4c2..c592ae090397932f24168267bb937261248a71ac 100644 --- a/drivers/media/dvb/siano/smscoreapi.h +++ b/drivers/media/dvb/siano/smscoreapi.h @@ -22,7 +22,6 @@ along with this program. If not, see . #ifndef __SMS_CORE_API_H__ #define __SMS_CORE_API_H__ -#include #include #include #include diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index 3d8cc425fa6b6206e394548e8abdf482f7aa3a73..25e58cbf35f0281c5c0bdad2d63d1075531d870a 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -102,10 +102,7 @@ /* * Version Information */ -#include /* for KERNEL_VERSION MACRO */ - -#define DRIVER_VERSION "v0.46" -#define RADIO_VERSION KERNEL_VERSION(0, 4, 6) +#define DRIVER_VERSION "0.4.7" #define DRIVER_AUTHOR "Markus Demleitner " #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver" @@ -335,7 +332,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, "dsbr100", sizeof(v->driver)); strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card)); usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); - v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER; return 0; } @@ -647,3 +643,4 @@ module_exit (dsbr100_exit); MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 4ce10dbeadd861c587ad274ccdd09e784b9a729e..1c3f8440a55cf113d7a9fc1850680ca0f16da869 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -33,7 +33,6 @@ #include /* request_region */ #include /* msleep */ #include /* kernel radio structs */ -#include /* for KERNEL_VERSION MACRO */ #include /* outb, outb_p */ #include #include @@ -41,6 +40,7 @@ MODULE_AUTHOR("M.Kirkwood"); MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card."); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.0.3"); #ifndef CONFIG_RADIO_RTRACK_PORT #define CONFIG_RADIO_RTRACK_PORT -1 @@ -53,8 +53,6 @@ module_param(io, int, 0); MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)"); module_param(radio_nr, int, 0); -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) - struct rtrack { struct v4l2_device v4l2_dev; @@ -223,7 +221,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, "radio-aimslab", sizeof(v->driver)); strlcpy(v->card, "RadioTrack", sizeof(v->card)); strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c index dd8a6ab0d437ab10022d1b65f1d802cc8d2b006c..eed7b08407340e3baebc12dd3493b0afd2e1cd44 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c @@ -30,7 +30,6 @@ #include /* request_region */ #include /* udelay */ #include /* kernel radio structs */ -#include /* for KERNEL_VERSION MACRO */ #include /* outb, outb_p */ #include #include @@ -38,6 +37,7 @@ MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); MODULE_DESCRIPTION("A driver for the Aztech radio card."); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.0.3"); /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ @@ -53,8 +53,6 @@ module_param(io, int, 0); module_param(radio_nr, int, 0); MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)"); -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) - struct aztech { struct v4l2_device v4l2_dev; @@ -188,7 +186,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, "radio-aztech", sizeof(v->driver)); strlcpy(v->card, "Aztech Radio", sizeof(v->card)); strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index bc9ad0897c559b9142aea9ba7cbf486caaf1d5c4..16a089fad909f241f76d6f5a8a1eb8b22f9358bb 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -30,7 +30,6 @@ * Changed API to V4L2 */ -#include #include /* Modules */ #include /* Initdata */ #include /* request_region */ @@ -46,6 +45,7 @@ MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card."); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.3.4"); static int io = -1; /* default to isapnp activation */ static int radio_nr = -1; @@ -54,8 +54,6 @@ module_param(io, int, 0); MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)"); module_param(radio_nr, int, 0); -#define CADET_VERSION KERNEL_VERSION(0, 3, 3) - #define RDS_BUFFER 256 #define RDS_RX_FLAG 1 #define MBS_RX_FLAG 2 @@ -361,7 +359,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, "ADS Cadet", sizeof(v->driver)); strlcpy(v->card, "ADS Cadet", sizeof(v->card)); strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = CADET_VERSION; v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE; return 0; diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 259936422e493b4dcf6dd6742d17bc5acd5b2995..edadc8449a3d109ab736afdd24f71058fb07b171 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -21,21 +21,19 @@ #include /* request_region */ #include /* udelay */ #include /* kernel radio structs */ -#include /* for KERNEL_VERSION MACRO */ #include #include /* outb, outb_p */ #include #include -#define RADIO_VERSION KERNEL_VERSION(0, 0, 3) - /* * Module info. */ -MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen "); +MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen "); MODULE_DESCRIPTION("A driver for the GemTek Radio card."); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.0.4"); /* * Module params. @@ -387,7 +385,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, "radio-gemtek", sizeof(v->driver)); strlcpy(v->card, "GemTek", sizeof(v->card)); strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index e83e84003025222f4a74d95024fa5df80f658ca8..f872a54cf3d9ae9baa03bdf9c5170664b9295d8f 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -40,15 +40,18 @@ #include #include #include -#include /* for KERNEL_VERSION MACRO */ #include #include #include #include +#define DRIVER_VERSION "0.7.8" + + MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net"); MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio."); MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); static int radio_nr = -1; module_param(radio_nr, int, 0); @@ -58,10 +61,6 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "activates debug info"); -#define DRIVER_VERSION "0.77" - -#define RADIO_VERSION KERNEL_VERSION(0, 7, 7) - #define dprintk(dev, num, fmt, arg...) \ v4l2_dbg(num, debug, &dev->v4l2_dev, fmt, ## arg) @@ -195,7 +194,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, "radio-maxiradio", sizeof(v->driver)); strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof(v->card)); snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev)); - v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index b3a635b9582013d92fd91f8f5aa51c3e0ce48d01..1742bd8110bdb3b28b175dcd2e9613e6aba9e189 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -63,18 +63,17 @@ #include #include #include -#include /* for KERNEL_VERSION MACRO */ #include /* driver and module definitions */ #define DRIVER_AUTHOR "Alexey Klimov " #define DRIVER_DESC "AverMedia MR 800 USB FM radio driver" -#define DRIVER_VERSION "0.11" -#define RADIO_VERSION KERNEL_VERSION(0, 1, 1) +#define DRIVER_VERSION "0.1.2" MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); #define USB_AMRADIO_VENDOR 0x07ca #define USB_AMRADIO_PRODUCT 0xb800 @@ -301,7 +300,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, "radio-mr800", sizeof(v->driver)); strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card)); usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); - v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER; return 0; } diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index 8d6ea591bd188815c374ddf5c5e603a5aa3d6e8e..3628be617ee9fb99c395f511b166b61c96798db1 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -15,7 +15,6 @@ #include /* udelay */ #include /* kernel radio structs */ #include -#include /* for KERNEL_VERSION MACRO */ #include /* outb, outb_p */ #include #include @@ -23,6 +22,7 @@ MODULE_AUTHOR("Ben Pfaff"); MODULE_DESCRIPTION("A driver for the RadioTrack II radio card."); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.0.3"); #ifndef CONFIG_RADIO_RTRACK2_PORT #define CONFIG_RADIO_RTRACK2_PORT -1 @@ -35,8 +35,6 @@ module_param(io, int, 0); MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)"); module_param(radio_nr, int, 0); -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) - struct rtrack2 { struct v4l2_device v4l2_dev; @@ -121,7 +119,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver)); strlcpy(v->card, "RadioTrack II", sizeof(v->card)); strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index b5a5f89e238a91fe432326d0da9487cf32ad9943..22c5743bf9db1d77a58bfa77949f14103892bcb8 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -16,7 +16,6 @@ * Converted to V4L2 API by Mauro Carvalho Chehab */ -#include #include /* __setup */ #include /* Modules */ #include /* Initdata */ @@ -32,6 +31,7 @@ MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood"); MODULE_DESCRIPTION("A driver for the SF16-FMI and SF16-FMP radio."); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.0.3"); static int io = -1; static int radio_nr = -1; @@ -40,8 +40,6 @@ module_param(io, int, 0); MODULE_PARM_DESC(io, "I/O address of the SF16-FMI or SF16-FMP card (0x284 or 0x384)"); module_param(radio_nr, int, 0); -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) - struct fmi { struct v4l2_device v4l2_dev; @@ -134,7 +132,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver)); strlcpy(v->card, "SF16-FMx radio", sizeof(v->card)); strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index 87bad7678d92f63bab822d6e8a244a6d6729fd69..2dd485996ba8e05ddd94b127e205590c1f34f6a9 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -1,441 +1,209 @@ -/* SF16FMR2 radio driver for Linux radio support - * heavily based on fmi driver... - * (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com +/* SF16-FMR2 radio driver for Linux + * Copyright (c) 2011 Ondrej Zary * - * Notes on the hardware - * - * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); - * No volume control - only mute/unmute - you have to use line volume - * - * For read stereo/mono you must wait 0.1 sec after set frequency and - * card unmuted so I set frequency on unmute - * Signal handling seem to work only on autoscanning (not implemented) - * - * Converted to V4L2 API by Mauro Carvalho Chehab + * Original driver was (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com + * but almost nothing remained here after conversion to generic TEA575x + * implementation */ +#include #include /* Modules */ #include /* Initdata */ #include /* request_region */ -#include /* udelay */ -#include /* kernel radio structs */ -#include -#include /* for KERNEL_VERSION MACRO */ #include /* outb, outb_p */ -#include -#include +#include -MODULE_AUTHOR("Ziglio Frediano, freddy77@angelfire.com"); -MODULE_DESCRIPTION("A driver for the SF16FMR2 radio."); +MODULE_AUTHOR("Ondrej Zary"); +MODULE_DESCRIPTION("MediaForte SF16-FMR2 FM radio card driver"); MODULE_LICENSE("GPL"); -static int io = 0x384; -static int radio_nr = -1; - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the SF16FMR2 card (should be 0x384, if do not work try 0x284)"); -module_param(radio_nr, int, 0); - -#define RADIO_VERSION KERNEL_VERSION(0,0,2) - -#define AUD_VOL_INDEX 1 - -#undef DEBUG -//#define DEBUG 1 - -#ifdef DEBUG -# define debug_print(s) printk s -#else -# define debug_print(s) -#endif - -/* this should be static vars for module size */ -struct fmr2 -{ - struct v4l2_device v4l2_dev; - struct video_device vdev; - struct mutex lock; +struct fmr2 { int io; - int curvol; /* 0-15 */ - int mute; - int stereo; /* card is producing stereo audio */ - unsigned long curfreq; /* freq in kHz */ - int card_type; + struct snd_tea575x tea; + struct v4l2_ctrl *volume; + struct v4l2_ctrl *balance; }; +/* the port is hardwired so no need to support multiple cards */ +#define FMR2_PORT 0x384 static struct fmr2 fmr2_card; -/* hw precision is 12.5 kHz - * It is only useful to give freq in interval of 200 (=0.0125Mhz), - * other bits will be truncated - */ -#define RSF16_ENCODE(x) ((x) / 200 + 856) -#define RSF16_MINFREQ (87 * 16000) -#define RSF16_MAXFREQ (108 * 16000) - -static inline void wait(int n, int io) -{ - for (; n; --n) - inb(io); -} - -static void outbits(int bits, unsigned int data, int nWait, int io) -{ - int bit; - - for (; --bits >= 0;) { - bit = (data >> bits) & 1; - outb(bit, io); - wait(nWait, io); - outb(bit | 2, io); - wait(nWait, io); - outb(bit, io); - wait(nWait, io); - } -} - -static inline void fmr2_mute(int io) -{ - outb(0x00, io); - wait(4, io); -} - -static inline void fmr2_unmute(int io) -{ - outb(0x04, io); - wait(4, io); -} - -static inline int fmr2_stereo_mode(int io) -{ - int n = inb(io); - - outb(6, io); - inb(io); - n = ((n >> 3) & 1) ^ 1; - debug_print((KERN_DEBUG "stereo: %d\n", n)); - return n; -} - -static int fmr2_product_info(struct fmr2 *dev) -{ - int n = inb(dev->io); - - n &= 0xC1; - if (n == 0) { - /* this should support volume set */ - dev->card_type = 12; - return 0; - } - /* not volume (mine is 11) */ - dev->card_type = (n == 128) ? 11 : 0; - return n; -} +/* TEA575x tuner pins */ +#define STR_DATA (1 << 0) +#define STR_CLK (1 << 1) +#define STR_WREN (1 << 2) +#define STR_MOST (1 << 3) +/* PT2254A/TC9154A volume control pins */ +#define PT_ST (1 << 4) +#define PT_CK (1 << 5) +#define PT_DATA (1 << 6) +/* volume control presence pin */ +#define FMR2_HASVOL (1 << 7) -static inline int fmr2_getsigstr(struct fmr2 *dev) +static void fmr2_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) { - /* !!! works only if scanning freq */ - int res = 0xffff; - - outb(5, dev->io); - wait(4, dev->io); - if (!(inb(dev->io) & 1)) - res = 0; - debug_print((KERN_DEBUG "signal: %d\n", res)); - return res; -} - -/* set frequency and unmute card */ -static int fmr2_setfreq(struct fmr2 *dev) -{ - unsigned long freq = dev->curfreq; - - fmr2_mute(dev->io); - - /* 0x42 for mono output - * 0x102 forward scanning - * 0x182 scansione avanti - */ - outbits(9, 0x2, 3, dev->io); - outbits(16, RSF16_ENCODE(freq), 2, dev->io); - - fmr2_unmute(dev->io); + struct fmr2 *fmr2 = tea->private_data; + u8 bits = 0; - /* wait 0.11 sec */ - msleep(110); + bits |= (pins & TEA575X_DATA) ? STR_DATA : 0; + bits |= (pins & TEA575X_CLK) ? STR_CLK : 0; + /* WRITE_ENABLE is inverted, DATA must be high during read */ + bits |= (pins & TEA575X_WREN) ? 0 : STR_WREN | STR_DATA; - /* NOTE if mute this stop radio - you must set freq on unmute */ - dev->stereo = fmr2_stereo_mode(dev->io); - return 0; -} - -/* !!! not tested, in my card this doesn't work !!! */ -static int fmr2_setvolume(struct fmr2 *dev) -{ - int vol[16] = { 0x021, 0x084, 0x090, 0x104, - 0x110, 0x204, 0x210, 0x402, - 0x404, 0x408, 0x410, 0x801, - 0x802, 0x804, 0x808, 0x810 }; - int i, a; - int n = vol[dev->curvol & 0x0f]; - - if (dev->card_type != 11) - return 1; - - for (i = 12; --i >= 0; ) { - a = ((n >> i) & 1) << 6; /* if (a==0) a = 0; else a = 0x40; */ - outb(a | 4, dev->io); - wait(4, dev->io); - outb(a | 0x24, dev->io); - wait(4, dev->io); - outb(a | 4, dev->io); - wait(4, dev->io); - } - for (i = 6; --i >= 0; ) { - a = ((0x18 >> i) & 1) << 6; - outb(a | 4, dev->io); - wait(4, dev->io); - outb(a | 0x24, dev->io); - wait(4, dev->io); - outb(a | 4, dev->io); - wait(4, dev->io); - } - wait(4, dev->io); - outb(0x14, dev->io); - return 0; + outb(bits, fmr2->io); } -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) +static u8 fmr2_tea575x_get_pins(struct snd_tea575x *tea) { - strlcpy(v->driver, "radio-sf16fmr2", sizeof(v->driver)); - strlcpy(v->card, "SF16-FMR2 radio", sizeof(v->card)); - strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct fmr2 *fmr2 = video_drvdata(file); - - if (v->index > 0) - return -EINVAL; + struct fmr2 *fmr2 = tea->private_data; + u8 bits = inb(fmr2->io); - strlcpy(v->name, "FM", sizeof(v->name)); - v->type = V4L2_TUNER_RADIO; - - v->rangelow = RSF16_MINFREQ; - v->rangehigh = RSF16_MAXFREQ; - v->rxsubchans = fmr2->stereo ? V4L2_TUNER_SUB_STEREO : - V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_STEREO; - mutex_lock(&fmr2->lock); - v->signal = fmr2_getsigstr(fmr2); - mutex_unlock(&fmr2->lock); - return 0; + return (bits & STR_DATA) ? TEA575X_DATA : 0 | + (bits & STR_MOST) ? TEA575X_MOST : 0; } -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) +static void fmr2_tea575x_set_direction(struct snd_tea575x *tea, bool output) { - return v->index ? -EINVAL : 0; } -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct fmr2 *fmr2 = video_drvdata(file); +static struct snd_tea575x_ops fmr2_tea_ops = { + .set_pins = fmr2_tea575x_set_pins, + .get_pins = fmr2_tea575x_get_pins, + .set_direction = fmr2_tea575x_set_direction, +}; - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - if (f->frequency < RSF16_MINFREQ || - f->frequency > RSF16_MAXFREQ) - return -EINVAL; - /* rounding in steps of 200 to match the freq - that will be used */ - fmr2->curfreq = (f->frequency / 200) * 200; - - /* set card freq (if not muted) */ - if (fmr2->curvol && !fmr2->mute) { - mutex_lock(&fmr2->lock); - fmr2_setfreq(fmr2); - mutex_unlock(&fmr2->lock); +/* TC9154A/PT2254A volume control */ + +/* 18-bit shift register bit definitions */ +#define TC9154A_ATT_MAJ_0DB (1 << 0) +#define TC9154A_ATT_MAJ_10DB (1 << 1) +#define TC9154A_ATT_MAJ_20DB (1 << 2) +#define TC9154A_ATT_MAJ_30DB (1 << 3) +#define TC9154A_ATT_MAJ_40DB (1 << 4) +#define TC9154A_ATT_MAJ_50DB (1 << 5) +#define TC9154A_ATT_MAJ_60DB (1 << 6) + +#define TC9154A_ATT_MIN_0DB (1 << 7) +#define TC9154A_ATT_MIN_2DB (1 << 8) +#define TC9154A_ATT_MIN_4DB (1 << 9) +#define TC9154A_ATT_MIN_6DB (1 << 10) +#define TC9154A_ATT_MIN_8DB (1 << 11) +/* bit 12 is ignored */ +#define TC9154A_CHANNEL_LEFT (1 << 13) +#define TC9154A_CHANNEL_RIGHT (1 << 14) +/* bits 15, 16, 17 must be 0 */ + +#define TC9154A_ATT_MAJ(x) (1 << x) +#define TC9154A_ATT_MIN(x) (1 << (7 + x)) + +static void tc9154a_set_pins(struct fmr2 *fmr2, u8 pins) +{ + if (!fmr2->tea.mute) + pins |= STR_WREN; + + outb(pins, fmr2->io); +} + +static void tc9154a_set_attenuation(struct fmr2 *fmr2, int att, u32 channel) +{ + int i; + u32 reg; + u8 bit; + + reg = TC9154A_ATT_MAJ(att / 10) | TC9154A_ATT_MIN((att % 10) / 2); + reg |= channel; + /* write 18-bit shift register, LSB first */ + for (i = 0; i < 18; i++) { + bit = reg & (1 << i) ? PT_DATA : 0; + tc9154a_set_pins(fmr2, bit); + udelay(5); + tc9154a_set_pins(fmr2, bit | PT_CK); + udelay(5); + tc9154a_set_pins(fmr2, bit); } - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct fmr2 *fmr2 = video_drvdata(file); - - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = fmr2->curfreq; - return 0; -} -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct fmr2 *fmr2 = video_drvdata(file); - - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - case V4L2_CID_AUDIO_VOLUME: - /* Only card_type == 11 implements volume */ - if (fmr2->card_type == 11) - return v4l2_ctrl_query_fill(qc, 0, 15, 1, 0); - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); - } - return -EINVAL; + /* latch register data */ + udelay(5); + tc9154a_set_pins(fmr2, PT_ST); + udelay(5); + tc9154a_set_pins(fmr2, 0); } -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) +static int fmr2_s_ctrl(struct v4l2_ctrl *ctrl) { - struct fmr2 *fmr2 = video_drvdata(file); + struct snd_tea575x *tea = container_of(ctrl->handler, struct snd_tea575x, ctrl_handler); + struct fmr2 *fmr2 = tea->private_data; + int volume, balance, left, right; switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = fmr2->mute; - return 0; case V4L2_CID_AUDIO_VOLUME: - ctrl->value = fmr2->curvol; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct fmr2 *fmr2 = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - fmr2->mute = ctrl->value; + volume = ctrl->val; + balance = fmr2->balance->cur.val; break; - case V4L2_CID_AUDIO_VOLUME: - fmr2->curvol = ctrl->value; + case V4L2_CID_AUDIO_BALANCE: + balance = ctrl->val; + volume = fmr2->volume->cur.val; break; default: return -EINVAL; } -#ifdef DEBUG - if (fmr2->curvol && !fmr2->mute) - printk(KERN_DEBUG "unmute\n"); - else - printk(KERN_DEBUG "mute\n"); -#endif - - mutex_lock(&fmr2->lock); - if (fmr2->curvol && !fmr2->mute) { - fmr2_setvolume(fmr2); - /* Set frequency and unmute card */ - fmr2_setfreq(fmr2); - } else - fmr2_mute(fmr2->io); - mutex_unlock(&fmr2->lock); - return 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} + left = right = volume; + if (balance < 0) + right = max(0, right + balance); + if (balance > 0) + left = max(0, left - balance); -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} + tc9154a_set_attenuation(fmr2, abs(left - 68), TC9154A_CHANNEL_LEFT); + tc9154a_set_attenuation(fmr2, abs(right - 68), TC9154A_CHANNEL_RIGHT); -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; return 0; } -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) +static const struct v4l2_ctrl_ops fmr2_ctrl_ops = { + .s_ctrl = fmr2_s_ctrl, +}; + +static int fmr2_tea_ext_init(struct snd_tea575x *tea) { - return a->index ? -EINVAL : 0; -} + struct fmr2 *fmr2 = tea->private_data; -static const struct v4l2_file_operations fmr2_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; + if (inb(fmr2->io) & FMR2_HASVOL) { + fmr2->volume = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_VOLUME, 0, 68, 2, 56); + fmr2->balance = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_BALANCE, -68, 68, 2, 0); + if (tea->ctrl_handler.error) { + printk(KERN_ERR "radio-sf16fmr2: can't initialize contrls\n"); + return tea->ctrl_handler.error; + } + } -static const struct v4l2_ioctl_ops fmr2_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; + return 0; +} static int __init fmr2_init(void) { struct fmr2 *fmr2 = &fmr2_card; - struct v4l2_device *v4l2_dev = &fmr2->v4l2_dev; - int res; - strlcpy(v4l2_dev->name, "sf16fmr2", sizeof(v4l2_dev->name)); - fmr2->io = io; - fmr2->stereo = 1; - mutex_init(&fmr2->lock); + fmr2->io = FMR2_PORT; - if (!request_region(fmr2->io, 2, "sf16fmr2")) { - v4l2_err(v4l2_dev, "request_region failed!\n"); + if (!request_region(fmr2->io, 2, "SF16-FMR2")) { + printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io); return -EBUSY; } - res = v4l2_device_register(NULL, v4l2_dev); - if (res < 0) { - release_region(fmr2->io, 2); - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return res; - } + fmr2->tea.private_data = fmr2; + fmr2->tea.ops = &fmr2_tea_ops; + fmr2->tea.ext_init = fmr2_tea_ext_init; + strlcpy(fmr2->tea.card, "SF16-FMR2", sizeof(fmr2->tea.card)); + strcpy(fmr2->tea.bus_info, "ISA"); - strlcpy(fmr2->vdev.name, v4l2_dev->name, sizeof(fmr2->vdev.name)); - fmr2->vdev.v4l2_dev = v4l2_dev; - fmr2->vdev.fops = &fmr2_fops; - fmr2->vdev.ioctl_ops = &fmr2_ioctl_ops; - fmr2->vdev.release = video_device_release_empty; - video_set_drvdata(&fmr2->vdev, fmr2); - - /* mute card - prevents noisy bootups */ - fmr2_mute(fmr2->io); - fmr2_product_info(fmr2); - - if (video_register_device(&fmr2->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(v4l2_dev); + if (snd_tea575x_init(&fmr2->tea)) { + printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n"); release_region(fmr2->io, 2); - return -EINVAL; + return -ENODEV; } - v4l2_info(v4l2_dev, "SF16FMR2 radio card driver at 0x%x.\n", fmr2->io); - debug_print((KERN_DEBUG "card_type %d\n", fmr2->card_type)); + printk(KERN_INFO "radio-sf16fmr2: SF16-FMR2 radio card at 0x%x.\n", fmr2->io); return 0; } @@ -443,22 +211,9 @@ static void __exit fmr2_exit(void) { struct fmr2 *fmr2 = &fmr2_card; - video_unregister_device(&fmr2->vdev); - v4l2_device_unregister(&fmr2->v4l2_dev); + snd_tea575x_exit(&fmr2->tea); release_region(fmr2->io, 2); } module_init(fmr2_init); module_exit(fmr2_exit); - -#ifndef MODULE - -static int __init fmr2_setup_io(char *str) -{ - get_option(&str, &io); - return 1; -} - -__setup("sf16fmr2=", fmr2_setup_io); - -#endif diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 0e71d816c725885535cc4d1da4f992809d0d6257..95ddcc4845d34d7563b6843ea5f51d8255555cdc 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -39,10 +39,8 @@ #include /* I2C */ #include #include -#include /* for KERNEL_VERSION MACRO */ -#define DRIVER_VERSION "v0.01" -#define RADIO_VERSION KERNEL_VERSION(0, 0, 1) +#define DRIVER_VERSION "0.0.2" #define DRIVER_AUTHOR "Fabio Belavenuto " #define DRIVER_DESC "A driver for the TEA5764 radio chip for EZX Phones." @@ -300,7 +298,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->card, dev->name, sizeof(v->card)); snprintf(v->bus_info, sizeof(v->bus_info), "I2C:%s", dev_name(&dev->dev)); - v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } @@ -595,8 +592,9 @@ static void __exit tea5764_exit(void) MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); -module_param(use_xtal, int, 1); +module_param(use_xtal, int, 0); MODULE_PARM_DESC(use_xtal, "Chip have a xtal connected in board"); module_param(radio_nr, int, 0); MODULE_PARM_DESC(radio_nr, "video4linux device number to use"); diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index a32663917059c1cd4734247452c33444c02ad5d2..f2ed9cc3cf3b7d6fcdd462f5ee82ff6dd414558e 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -29,7 +29,6 @@ #include /* request_region */ #include /* kernel radio structs */ #include -#include /* for KERNEL_VERSION MACRO */ #include /* outb, outb_p */ #include #include @@ -37,6 +36,7 @@ MODULE_AUTHOR("R.OFFERMANNS & others"); MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card."); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.0.3"); #ifndef CONFIG_RADIO_TERRATEC_PORT #define CONFIG_RADIO_TERRATEC_PORT 0x590 @@ -49,8 +49,6 @@ module_param(io, int, 0); MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)"); module_param(radio_nr, int, 0); -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) - static struct v4l2_queryctrl radio_qctrl[] = { { .id = V4L2_CID_AUDIO_MUTE, @@ -205,7 +203,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, "radio-terratec", sizeof(v->driver)); strlcpy(v->card, "ActiveRadio", sizeof(v->card)); strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index a185610b376be1a14e79b52751c7f95aab777dd0..f17b540d68a5e257662ab82afd1020ebce70872c 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -16,7 +16,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include @@ -44,7 +43,6 @@ static int timbradio_vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, DRIVER_NAME, sizeof(v->driver)); strlcpy(v->card, "Timberdale Radio", sizeof(v->card)); snprintf(v->bus_info, sizeof(v->bus_info), "platform:"DRIVER_NAME); - v->version = KERNEL_VERSION(0, 0, 1); v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } @@ -245,4 +243,5 @@ module_exit(timbradio_exit); MODULE_DESCRIPTION("Timberdale Radio driver"); MODULE_AUTHOR("Mocean Laboratories "); MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.0.2"); MODULE_ALIAS("platform:"DRIVER_NAME); diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index 22fa9cc28abed060cff57e1e3a78227575c9ee36..b3f45a019d82c875432e1d6c1c3ca6f47179af9e 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c @@ -19,7 +19,6 @@ #include #include #include -#include /* for KERNEL_VERSION MACRO */ #include #include #include @@ -28,6 +27,7 @@ MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); MODULE_DESCRIPTION("A driver for the Trust FM Radio card."); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.0.3"); /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ @@ -42,8 +42,6 @@ module_param(io, int, 0); MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)"); module_param(radio_nr, int, 0); -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) - struct trust { struct v4l2_device v4l2_dev; struct video_device vdev; @@ -196,7 +194,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, "radio-trust", sizeof(v->driver)); strlcpy(v->card, "Trust FM Radio", sizeof(v->card)); strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index 8dbbf08f22077ad2b7c84e8e3992d3b33eab88e7..398726abc0c863947bdf873bd4ff075880904fc4 100644 --- a/drivers/media/radio/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c @@ -31,15 +31,17 @@ #include /* Modules */ #include /* Initdata */ #include /* request_region */ -#include /* for KERNEL_VERSION MACRO */ #include /* kernel radio structs */ #include /* outb, outb_p */ #include #include +#define DRIVER_VERSION "0.1.2" + MODULE_AUTHOR("Dr. Henrik Seidel"); MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio)."); MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); #ifndef CONFIG_RADIO_TYPHOON_PORT #define CONFIG_RADIO_TYPHOON_PORT -1 @@ -61,9 +63,7 @@ static unsigned long mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ; module_param(mutefreq, ulong, 0); MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)"); -#define RADIO_VERSION KERNEL_VERSION(0, 1, 1) - -#define BANNER "Typhoon Radio Card driver v0.1.1\n" +#define BANNER "Typhoon Radio Card driver v" DRIVER_VERSION "\n" struct typhoon { struct v4l2_device v4l2_dev; @@ -171,7 +171,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, "radio-typhoon", sizeof(v->driver)); strlcpy(v->card, "Typhoon Radio", sizeof(v->card)); strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 459f7272d32634d67143ee679a5375fc85f37f99..46cacf845049941c5ad0efc687e23fd2ad4236d7 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1382,7 +1382,7 @@ static int wl1273_fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - ctrl->cur.val = wl1273_fm_get_tx_ctune(radio); + ctrl->val = wl1273_fm_get_tx_ctune(radio); break; default: diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index af99c5bd88c1f0ce15311ec63c137aeee2ce42ab..f5613b94820353f1744d4f7fff50c42e9be77a69 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c @@ -35,7 +35,6 @@ #include /* udelay, msleep */ #include /* kernel radio structs */ #include -#include /* for KERNEL_VERSION MACRO */ #include /* outb, outb_p */ #include #include @@ -43,6 +42,7 @@ MODULE_AUTHOR("C.van Schaik"); MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus."); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.0.3"); #ifndef CONFIG_RADIO_ZOLTRIX_PORT #define CONFIG_RADIO_ZOLTRIX_PORT -1 @@ -55,8 +55,6 @@ module_param(io, int, 0); MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)"); module_param(radio_nr, int, 0); -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) - struct zoltrix { struct v4l2_device v4l2_dev; struct video_device vdev; @@ -228,7 +226,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver)); strlcpy(v->card, "Zoltrix Radio", sizeof(v->card)); strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index a2a67772c42c93695881f7f421fc78a1f6e220fe..fd3541b0e91c74e8fd4515437dad483344e49a45 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -24,10 +24,9 @@ /* driver definitions */ #define DRIVER_AUTHOR "Joonyoung Shim "; -#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 1) #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" #define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers" -#define DRIVER_VERSION "1.0.1" +#define DRIVER_VERSION "1.0.2" /* kernel includes */ #include @@ -248,7 +247,6 @@ int si470x_vidioc_querycap(struct file *file, void *priv, { strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); - capability->version = DRIVER_KERNEL_VERSION; capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | V4L2_CAP_RADIO; diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index 392e84fe90ef9f4c1ffee33c99197f776ad338b6..4cf537043f99ec420ae8ebb6f960642a72bf9a5c 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -29,7 +29,6 @@ /* driver definitions */ #define DRIVER_AUTHOR "Tobias Lorenz " -#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 10) #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" #define DRIVER_VERSION "1.0.10" @@ -626,7 +625,6 @@ int si470x_vidioc_querycap(struct file *file, void *priv, strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); usb_make_path(radio->usbdev, capability->bus_info, sizeof(capability->bus_info)); - capability->version = DRIVER_KERNEL_VERSION; capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; @@ -699,7 +697,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, radio->videodev = video_device_alloc(); if (!radio->videodev) { retval = -ENOMEM; - goto err_intbuffer; + goto err_urb; } memcpy(radio->videodev, &si470x_viddev_template, sizeof(si470x_viddev_template)); @@ -790,6 +788,8 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, kfree(radio->buffer); err_video: video_device_release(radio->videodev); +err_urb: + usb_free_urb(radio->int_in_urb); err_intbuffer: kfree(radio->int_in_buffer); err_radio: diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h index 68da001b09dc48f97b110f1602eaee1102443444..f300a55ed85ccee217f3a8ff37565e0fcc5a7d6f 100644 --- a/drivers/media/radio/si470x/radio-si470x.h +++ b/drivers/media/radio/si470x/radio-si470x.h @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/radio/wl128x/fmdrv.h b/drivers/media/radio/wl128x/fmdrv.h index 1a45a5d847b089d1b7752ecf3c7e61cf9b115d05..d84ad9dad323c25bea0e7b0972c1e3f72295ff28 100644 --- a/drivers/media/radio/wl128x/fmdrv.h +++ b/drivers/media/radio/wl128x/fmdrv.h @@ -28,14 +28,11 @@ #include #include #include -#include #include #include #include -#define FM_DRV_VERSION "0.10" -/* Should match with FM_DRV_VERSION */ -#define FM_DRV_RADIO_VERSION KERNEL_VERSION(0, 0, 1) +#define FM_DRV_VERSION "0.1.1" #define FM_DRV_NAME "ti_fmdrv" #define FM_DRV_CARD_SHORT_NAME "TI FM Radio" #define FM_DRV_CARD_LONG_NAME "Texas Instruments FM Radio" diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index 87010724f9147b53170dc59f1e603115ae2fd72c..8c0e19276970543490fa02b07209825c897e2828 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -175,7 +175,6 @@ static int fm_v4l2_vidioc_querycap(struct file *file, void *priv, strlcpy(capability->card, FM_DRV_CARD_SHORT_NAME, sizeof(capability->card)); sprintf(capability->bus_info, "UART"); - capability->version = FM_DRV_RADIO_VERSION; capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_MODULATOR | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | @@ -191,7 +190,7 @@ static int fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - ctrl->cur.val = fm_tx_get_tune_cap_val(fmdev); + ctrl->val = fm_tx_get_tune_cap_val(fmdev); break; default: fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id); diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 7d4bbc226d068dd263a18b9ee69c70793245669f..899f783d92fbb4e91d35fd1e8395a86a1732794c 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -87,6 +87,17 @@ config IR_RC5_SZ_DECODER uses an IR protocol that is almost standard RC-5, but not quite, as it uses an additional bit). +config IR_MCE_KBD_DECODER + tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol" + depends on RC_CORE + select BITREVERSE + default y + + ---help--- + Enable this option if you have a Microsoft Remote Keyboard for + Windows Media Center Edition, which you would like to use with + a raw IR receiver in your system. + config IR_LIRC_CODEC tristate "Enable IR to LIRC bridge" depends on RC_CORE diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 52830e5f4eaaa4ee184fc20ff0ece6e3f3809ace..f224db027c411ecdaf8ddfa69f5bec43e2b1d05f 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o +obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o # stand-alone IR receivers/transmitters diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index a43ed6c41bfc475361fd9b0155826dfd69a3746e..2b9c2569d74a2163888769e41045e97a7a5fc642 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -953,13 +953,13 @@ static void ene_set_idle(struct rc_dev *rdev, bool idle) } /* outside interface: transmit */ -static int ene_transmit(struct rc_dev *rdev, int *buf, u32 n) +static int ene_transmit(struct rc_dev *rdev, unsigned *buf, unsigned n) { struct ene_device *dev = rdev->priv; unsigned long flags; dev->tx_buffer = buf; - dev->tx_len = n / sizeof(int); + dev->tx_len = n; dev->tx_pos = 0; dev->tx_reg = 0; dev->tx_done = 0; diff --git a/drivers/media/rc/ene_ir.h b/drivers/media/rc/ene_ir.h index 337a41d4450ba2aee45171cfc7e92117baf7e24e..017c209cdf8a2ac51ae7365908102e8dc4e8a10d 100644 --- a/drivers/media/rc/ene_ir.h +++ b/drivers/media/rc/ene_ir.h @@ -235,7 +235,7 @@ struct ene_device { bool tx_sample_pulse; /* current sample is pulse */ /* TX buffer */ - int *tx_buffer; /* input samples buffer*/ + unsigned *tx_buffer; /* input samples buffer*/ int tx_pos; /* position in that bufer */ int tx_len; /* current len of tx buffer */ int tx_done; /* done transmitting */ diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 1c5cc65ea1e11463c9ba6998f48c1947988e842a..e5eeec4da76ea776972cc202ac4367605dd999bb 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -103,19 +103,19 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf, { struct lirc_codec *lirc; struct rc_dev *dev; - int *txbuf; /* buffer with values to transmit */ - int ret = 0; + unsigned int *txbuf; /* buffer with values to transmit */ + ssize_t ret = 0; size_t count; lirc = lirc_get_pdata(file); if (!lirc) return -EFAULT; - if (n % sizeof(int)) + if (n < sizeof(unsigned) || n % sizeof(unsigned)) return -EINVAL; - count = n / sizeof(int); - if (count > LIRCBUF_SIZE || count % 2 == 0 || n % sizeof(int) != 0) + count = n / sizeof(unsigned); + if (count > LIRCBUF_SIZE || count % 2 == 0) return -EINVAL; txbuf = memdup_user(buf, n); @@ -129,7 +129,10 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf, } if (dev->tx_ir) - ret = dev->tx_ir(dev, txbuf, (u32)n); + ret = dev->tx_ir(dev, txbuf, count); + + if (ret > 0) + ret *= sizeof(unsigned); out: kfree(txbuf); diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c new file mode 100644 index 0000000000000000000000000000000000000000..3784ebf80ec7d9e162b95aab58434ef40d9d21c8 --- /dev/null +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -0,0 +1,449 @@ +/* ir-mce_kbd-decoder.c - A decoder for the RC6-ish keyboard/mouse IR protocol + * used by the Microsoft Remote Keyboard for Windows Media Center Edition, + * referred to by Microsoft's Windows Media Center remote specification docs + * as "an internal protocol called MCIR-2". + * + * Copyright (C) 2011 by Jarod Wilson + * + * 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 version 2 of the License. + * + * 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. + */ +#include + +#include "rc-core-priv.h" + +/* + * This decoder currently supports: + * - MCIR-2 29-bit IR signals used for mouse movement and buttons + * - MCIR-2 32-bit IR signals used for standard keyboard keys + * + * The media keys on the keyboard send RC-6 signals that are inditinguishable + * from the keys of the same name on the stock MCE remote, and will be handled + * by the standard RC-6 decoder, and be made available to the system via the + * input device for the remote, rather than the keyboard/mouse one. + */ + +#define MCIR2_UNIT 333333 /* ns */ +#define MCIR2_HEADER_NBITS 5 +#define MCIR2_MOUSE_NBITS 29 +#define MCIR2_KEYBOARD_NBITS 32 +#define MCIR2_PREFIX_PULSE (8 * MCIR2_UNIT) +#define MCIR2_PREFIX_SPACE (1 * MCIR2_UNIT) +#define MCIR2_MAX_LEN (3 * MCIR2_UNIT) +#define MCIR2_BIT_START (1 * MCIR2_UNIT) +#define MCIR2_BIT_END (1 * MCIR2_UNIT) +#define MCIR2_BIT_0 (1 * MCIR2_UNIT) +#define MCIR2_BIT_SET (2 * MCIR2_UNIT) +#define MCIR2_MODE_MASK 0xf /* for the header bits */ +#define MCIR2_KEYBOARD_HEADER 0x4 +#define MCIR2_MOUSE_HEADER 0x1 +#define MCIR2_MASK_KEYS_START 0xe0 + +enum mce_kbd_mode { + MCIR2_MODE_KEYBOARD, + MCIR2_MODE_MOUSE, + MCIR2_MODE_UNKNOWN, +}; + +enum mce_kbd_state { + STATE_INACTIVE, + STATE_HEADER_BIT_START, + STATE_HEADER_BIT_END, + STATE_BODY_BIT_START, + STATE_BODY_BIT_END, + STATE_FINISHED, +}; + +static unsigned char kbd_keycodes[256] = { + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_A, + KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, + KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, + KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, + KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, + KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, + KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, + KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, + KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, + KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, + KEY_RESERVED, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, + KEY_DOT, KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2, + KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, + KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, + KEY_SYSRQ, KEY_SCROLLLOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME, + KEY_PAGEUP, KEY_DELETE, KEY_END, KEY_PAGEDOWN, KEY_RIGHT, + KEY_LEFT, KEY_DOWN, KEY_UP, KEY_NUMLOCK, KEY_KPSLASH, + KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS, KEY_KPENTER, KEY_KP1, + KEY_KP2, KEY_KP3, KEY_KP4, KEY_KP5, KEY_KP6, + KEY_KP7, KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT, + KEY_102ND, KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL, KEY_F13, + KEY_F14, KEY_F15, KEY_F16, KEY_F17, KEY_F18, + KEY_F19, KEY_F20, KEY_F21, KEY_F22, KEY_F23, + KEY_F24, KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT, + KEY_STOP, KEY_AGAIN, KEY_UNDO, KEY_CUT, KEY_COPY, + KEY_PASTE, KEY_FIND, KEY_MUTE, KEY_VOLUMEUP, KEY_VOLUMEDOWN, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_KPCOMMA, KEY_RESERVED, + KEY_RO, KEY_KATAKANAHIRAGANA, KEY_YEN, KEY_HENKAN, KEY_MUHENKAN, + KEY_KPJPCOMMA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_HANGUEL, + KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA, KEY_ZENKAKUHANKAKU, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_LEFTCTRL, + KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT, + KEY_RIGHTALT, KEY_RIGHTMETA, KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG, + KEY_NEXTSONG, KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE, + KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP, KEY_FIND, + KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT, KEY_SLEEP, KEY_COFFEE, + KEY_REFRESH, KEY_CALC, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED +}; + +static void mce_kbd_rx_timeout(unsigned long data) +{ + struct mce_kbd_dec *mce_kbd = (struct mce_kbd_dec *)data; + int i; + unsigned char maskcode; + + IR_dprintk(2, "timer callback clearing all keys\n"); + + for (i = 0; i < 7; i++) { + maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i]; + input_report_key(mce_kbd->idev, maskcode, 0); + } + + for (i = 0; i < MCIR2_MASK_KEYS_START; i++) + input_report_key(mce_kbd->idev, kbd_keycodes[i], 0); +} + +static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data) +{ + switch (data->header & MCIR2_MODE_MASK) { + case MCIR2_KEYBOARD_HEADER: + return MCIR2_MODE_KEYBOARD; + case MCIR2_MOUSE_HEADER: + return MCIR2_MODE_MOUSE; + default: + return MCIR2_MODE_UNKNOWN; + } +} + +static void ir_mce_kbd_process_keyboard_data(struct input_dev *idev, + u32 scancode) +{ + u8 keydata = (scancode >> 8) & 0xff; + u8 shiftmask = scancode & 0xff; + unsigned char keycode, maskcode; + int i, keystate; + + IR_dprintk(1, "keyboard: keydata = 0x%02x, shiftmask = 0x%02x\n", + keydata, shiftmask); + + for (i = 0; i < 7; i++) { + maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i]; + if (shiftmask & (1 << i)) + keystate = 1; + else + keystate = 0; + input_report_key(idev, maskcode, keystate); + } + + if (keydata) { + keycode = kbd_keycodes[keydata]; + input_report_key(idev, keycode, 1); + } else { + for (i = 0; i < MCIR2_MASK_KEYS_START; i++) + input_report_key(idev, kbd_keycodes[i], 0); + } +} + +static void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode) +{ + /* raw mouse coordinates */ + u8 xdata = (scancode >> 7) & 0x7f; + u8 ydata = (scancode >> 14) & 0x7f; + int x, y; + /* mouse buttons */ + bool right = scancode & 0x40; + bool left = scancode & 0x20; + + if (xdata & 0x40) + x = -((~xdata & 0x7f) + 1); + else + x = xdata; + + if (ydata & 0x40) + y = -((~ydata & 0x7f) + 1); + else + y = ydata; + + IR_dprintk(1, "mouse: x = %d, y = %d, btns = %s%s\n", + x, y, left ? "L" : "", right ? "R" : ""); + + input_report_rel(idev, REL_X, x); + input_report_rel(idev, REL_Y, y); + + input_report_key(idev, BTN_LEFT, left); + input_report_key(idev, BTN_RIGHT, right); +} + +/** + * ir_mce_kbd_decode() - Decode one mce_kbd pulse or space + * @dev: the struct rc_dev descriptor of the device + * @ev: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine + */ +static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct mce_kbd_dec *data = &dev->raw->mce_kbd; + u32 scancode; + unsigned long delay; + + if (!(dev->raw->enabled_protocols & RC_TYPE_MCE_KBD)) + return 0; + + if (!is_timing_event(ev)) { + if (ev.reset) + data->state = STATE_INACTIVE; + return 0; + } + + if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2)) + goto out; + +again: + IR_dprintk(2, "started at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + + if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2)) + return 0; + + switch (data->state) { + + case STATE_INACTIVE: + if (!ev.pulse) + break; + + /* Note: larger margin on first pulse since each MCIR2_UNIT + is quite short and some hardware takes some time to + adjust to the signal */ + if (!eq_margin(ev.duration, MCIR2_PREFIX_PULSE, MCIR2_UNIT)) + break; + + data->state = STATE_HEADER_BIT_START; + data->count = 0; + data->header = 0; + return 0; + + case STATE_HEADER_BIT_START: + if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2)) + break; + + data->header <<= 1; + if (ev.pulse) + data->header |= 1; + data->count++; + data->state = STATE_HEADER_BIT_END; + return 0; + + case STATE_HEADER_BIT_END: + if (!is_transition(&ev, &dev->raw->prev_ev)) + break; + + decrease_duration(&ev, MCIR2_BIT_END); + + if (data->count != MCIR2_HEADER_NBITS) { + data->state = STATE_HEADER_BIT_START; + goto again; + } + + switch (mce_kbd_mode(data)) { + case MCIR2_MODE_KEYBOARD: + data->wanted_bits = MCIR2_KEYBOARD_NBITS; + break; + case MCIR2_MODE_MOUSE: + data->wanted_bits = MCIR2_MOUSE_NBITS; + break; + default: + IR_dprintk(1, "not keyboard or mouse data\n"); + goto out; + } + + data->count = 0; + data->body = 0; + data->state = STATE_BODY_BIT_START; + goto again; + + case STATE_BODY_BIT_START: + if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2)) + break; + + data->body <<= 1; + if (ev.pulse) + data->body |= 1; + data->count++; + data->state = STATE_BODY_BIT_END; + return 0; + + case STATE_BODY_BIT_END: + if (!is_transition(&ev, &dev->raw->prev_ev)) + break; + + if (data->count == data->wanted_bits) + data->state = STATE_FINISHED; + else + data->state = STATE_BODY_BIT_START; + + decrease_duration(&ev, MCIR2_BIT_END); + goto again; + + case STATE_FINISHED: + if (ev.pulse) + break; + + switch (data->wanted_bits) { + case MCIR2_KEYBOARD_NBITS: + scancode = data->body & 0xffff; + IR_dprintk(1, "keyboard data 0x%08x\n", data->body); + if (dev->timeout) + delay = usecs_to_jiffies(dev->timeout / 1000); + else + delay = msecs_to_jiffies(100); + mod_timer(&data->rx_timeout, jiffies + delay); + /* Pass data to keyboard buffer parser */ + ir_mce_kbd_process_keyboard_data(data->idev, scancode); + break; + case MCIR2_MOUSE_NBITS: + scancode = data->body & 0x1fffff; + IR_dprintk(1, "mouse data 0x%06x\n", scancode); + /* Pass data to mouse buffer parser */ + ir_mce_kbd_process_mouse_data(data->idev, scancode); + break; + default: + IR_dprintk(1, "not keyboard or mouse data\n"); + goto out; + } + + data->state = STATE_INACTIVE; + input_sync(data->idev); + return 0; + } + +out: + IR_dprintk(1, "failed at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + data->state = STATE_INACTIVE; + input_sync(data->idev); + return -EINVAL; +} + +static int ir_mce_kbd_register(struct rc_dev *dev) +{ + struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd; + struct input_dev *idev; + int i, ret; + + idev = input_allocate_device(); + if (!idev) + return -ENOMEM; + + snprintf(mce_kbd->name, sizeof(mce_kbd->name), + "MCE IR Keyboard/Mouse (%s)", dev->driver_name); + strlcat(mce_kbd->phys, "/input0", sizeof(mce_kbd->phys)); + + idev->name = mce_kbd->name; + idev->phys = mce_kbd->phys; + + /* Keyboard bits */ + set_bit(EV_KEY, idev->evbit); + set_bit(EV_REP, idev->evbit); + for (i = 0; i < sizeof(kbd_keycodes); i++) + set_bit(kbd_keycodes[i], idev->keybit); + + /* Mouse bits */ + set_bit(EV_REL, idev->evbit); + set_bit(REL_X, idev->relbit); + set_bit(REL_Y, idev->relbit); + set_bit(BTN_LEFT, idev->keybit); + set_bit(BTN_RIGHT, idev->keybit); + + /* Report scancodes too */ + set_bit(EV_MSC, idev->evbit); + set_bit(MSC_SCAN, idev->mscbit); + + setup_timer(&mce_kbd->rx_timeout, mce_kbd_rx_timeout, + (unsigned long)mce_kbd); + + input_set_drvdata(idev, mce_kbd); + +#if 0 + /* Adding this reference means two input devices are associated with + * this rc-core device, which ir-keytable doesn't cope with yet */ + idev->dev.parent = &dev->dev; +#endif + + ret = input_register_device(idev); + if (ret < 0) { + input_free_device(idev); + return -EIO; + } + + mce_kbd->idev = idev; + + return 0; +} + +static int ir_mce_kbd_unregister(struct rc_dev *dev) +{ + struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd; + struct input_dev *idev = mce_kbd->idev; + + del_timer_sync(&mce_kbd->rx_timeout); + input_unregister_device(idev); + + return 0; +} + +static struct ir_raw_handler mce_kbd_handler = { + .protocols = RC_TYPE_MCE_KBD, + .decode = ir_mce_kbd_decode, + .raw_register = ir_mce_kbd_register, + .raw_unregister = ir_mce_kbd_unregister, +}; + +static int __init ir_mce_kbd_decode_init(void) +{ + ir_raw_handler_register(&mce_kbd_handler); + + printk(KERN_INFO "IR MCE Keyboard/mouse protocol handler initialized\n"); + return 0; +} + +static void __exit ir_mce_kbd_decode_exit(void) +{ + ir_raw_handler_unregister(&mce_kbd_handler); +} + +module_init(ir_mce_kbd_decode_init); +module_exit(ir_mce_kbd_decode_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jarod Wilson "); +MODULE_DESCRIPTION("MCE Keyboard/mouse IR protocol decoder"); diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c index 423ed45d6c55a4e3ccb43f3ae1284bcf55d952da..27808bb59eba3874ee7c1c07f79ba67f82abfd78 100644 --- a/drivers/media/rc/ir-raw.c +++ b/drivers/media/rc/ir-raw.c @@ -355,6 +355,7 @@ static void init_decoders(struct work_struct *work) load_rc6_decode(); load_jvc_decode(); load_sony_decode(); + load_mce_kbd_decode(); load_lirc_codec(); /* If needed, we may later add some init code. In this case, diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index d20168fe4c40a673301af4ea985c9c1f18e4ce72..682009d76cdfe487ffe950c17235075808893795 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -382,7 +382,7 @@ static int ite_set_tx_duty_cycle(struct rc_dev *rcdev, u32 duty_cycle) /* transmit out IR pulses; what you get here is a batch of alternating * pulse/space/pulse/space lengths that we should write out completely through * the FIFO, blocking on a full FIFO */ -static int ite_tx_ir(struct rc_dev *rcdev, int *txbuf, u32 n) +static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n) { unsigned long flags; struct ite_dev *dev = rcdev->priv; @@ -398,9 +398,6 @@ static int ite_tx_ir(struct rc_dev *rcdev, int *txbuf, u32 n) /* clear the array just in case */ memset(last_sent, 0, ARRAY_SIZE(last_sent)); - /* n comes in bytes; convert to ints */ - n /= sizeof(int); - spin_lock_irqsave(&dev->lock, flags); /* let everybody know we're now transmitting */ diff --git a/drivers/media/rc/keymaps/rc-rc6-mce.c b/drivers/media/rc/keymaps/rc-rc6-mce.c index 01b69bcc86667e9e40bbb75eaeabdbe6994afa53..c3907e211d397bd7dadb36b46ec184d3b29d1884 100644 --- a/drivers/media/rc/keymaps/rc-rc6-mce.c +++ b/drivers/media/rc/keymaps/rc-rc6-mce.c @@ -29,7 +29,7 @@ static struct rc_map_table rc6_mce[] = { { 0x800f040a, KEY_DELETE }, { 0x800f040b, KEY_ENTER }, - { 0x800f040c, KEY_POWER }, /* PC Power */ + { 0x800f040c, KEY_SLEEP }, /* Formerly PC Power */ { 0x800f040d, KEY_MEDIA }, /* Windows MCE button */ { 0x800f040e, KEY_MUTE }, { 0x800f040f, KEY_INFO }, @@ -44,7 +44,6 @@ static struct rc_map_table rc6_mce[] = { { 0x800f0416, KEY_PLAY }, { 0x800f0417, KEY_RECORD }, { 0x800f0418, KEY_PAUSE }, - { 0x800f046e, KEY_PLAYPAUSE }, { 0x800f0419, KEY_STOP }, { 0x800f041a, KEY_NEXT }, { 0x800f041b, KEY_PREVIOUS }, diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index ec972dc25790ea8b18e2641a0e045e1f5858bc3f..85ff9a1ffb391b4ccfa291539e027ffa2c8d10da 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -692,20 +692,18 @@ static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size) } /* Send data out the IR blaster port(s) */ -static int mceusb_tx_ir(struct rc_dev *dev, int *txbuf, u32 n) +static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) { struct mceusb_dev *ir = dev->priv; int i, ret = 0; - int count, cmdcount = 0; + int cmdcount = 0; unsigned char *cmdbuf; /* MCE command buffer */ long signal_duration = 0; /* Singnal length in us */ struct timeval start_time, end_time; do_gettimeofday(&start_time); - count = n / sizeof(int); - - cmdbuf = kzalloc(sizeof(int) * MCE_CMDBUF_SIZE, GFP_KERNEL); + cmdbuf = kzalloc(sizeof(unsigned) * MCE_CMDBUF_SIZE, GFP_KERNEL); if (!cmdbuf) return -ENOMEM; @@ -774,7 +772,7 @@ static int mceusb_tx_ir(struct rc_dev *dev, int *txbuf, u32 n) out: kfree(cmdbuf); - return ret ? ret : n; + return ret ? ret : count; } /* Sets active IR outputs -- mce devices typically have two */ diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index ce595f9ab4c7a41c16ff0d69ecc33faf9fc3c4f4..eae05b5004761d334519a8aca4784b2db815f959 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -546,24 +546,18 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier) * number may larger than TXFCONT (0xff). So in interrupt_handler, it has to * set TXFCONT as 0xff, until buf_count less than 0xff. */ -static int nvt_tx_ir(struct rc_dev *dev, int *txbuf, u32 n) +static int nvt_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned n) { struct nvt_dev *nvt = dev->priv; unsigned long flags; - size_t cur_count; unsigned int i; u8 iren; int ret; spin_lock_irqsave(&nvt->tx.lock, flags); - if (n >= TX_BUF_LEN) { - nvt->tx.buf_count = cur_count = TX_BUF_LEN; - ret = TX_BUF_LEN; - } else { - nvt->tx.buf_count = cur_count = n; - ret = n; - } + ret = min((unsigned)(TX_BUF_LEN / sizeof(unsigned)), n); + nvt->tx.buf_count = (ret * sizeof(unsigned)); memcpy(nvt->tx.buf, txbuf, nvt->tx.buf_count); diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 873b387897511f59b446bfe4a9a94659a8f0611c..04c2c722b6ece48d9ead508e952b6e4ab4927328 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -84,6 +84,17 @@ struct ir_raw_event_ctrl { unsigned count; unsigned wanted_bits; } rc5_sz; + struct mce_kbd_dec { + struct input_dev *idev; + struct timer_list rx_timeout; + char name[64]; + char phys[64]; + int state; + u8 header; + u32 body; + unsigned count; + unsigned wanted_bits; + } mce_kbd; struct lirc_codec { struct rc_dev *dev; struct lirc_driver *drv; @@ -182,6 +193,13 @@ void ir_raw_init(void); #define load_sony_decode() 0 #endif +/* from ir-mce_kbd-decoder.c */ +#ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE +#define load_mce_kbd_decode() request_module("ir-mce_kbd-decoder") +#else +#define load_mce_kbd_decode() 0 +#endif + /* from ir-lirc-codec.c */ #ifdef CONFIG_IR_LIRC_CODEC_MODULE #define load_lirc_codec() request_module("ir-lirc-codec") diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c index cc846b2619cf38bb6f77d2a35ad8d2167dfc5bf1..efc6a514348afc394836026ddb885b328b6bc1ac 100644 --- a/drivers/media/rc/rc-loopback.c +++ b/drivers/media/rc/rc-loopback.c @@ -101,21 +101,14 @@ static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max) return 0; } -static int loop_tx_ir(struct rc_dev *dev, int *txbuf, u32 n) +static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) { struct loopback_dev *lodev = dev->priv; u32 rxmask; - unsigned count; unsigned total_duration = 0; unsigned i; DEFINE_IR_RAW_EVENT(rawir); - if (n == 0 || n % sizeof(int)) { - dprintk("invalid tx buffer size\n"); - return -EINVAL; - } - - count = n / sizeof(int); for (i = 0; i < count; i++) total_duration += abs(txbuf[i]); @@ -142,7 +135,7 @@ static int loop_tx_ir(struct rc_dev *dev, int *txbuf, u32 n) for (i = 0; i < count; i++) { rawir.pulse = i % 2 ? false : true; - rawir.duration = abs(txbuf[i]) * 1000; + rawir.duration = txbuf[i] * 1000; if (rawir.duration) ir_raw_event_store_with_filter(dev, &rawir); } @@ -158,7 +151,7 @@ static int loop_tx_ir(struct rc_dev *dev, int *txbuf, u32 n) /* Lirc expects this function to take as long as the total duration */ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(usecs_to_jiffies(total_duration)); - return n; + return count; } static void loop_set_idle(struct rc_dev *dev, bool enable) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 3186ac7c2c108c00d4346076d4bc20fc0d765df2..51a23f48bc7d83f99eed629a32188083f22786c3 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -735,6 +735,7 @@ static struct { { RC_TYPE_JVC, "jvc" }, { RC_TYPE_SONY, "sony" }, { RC_TYPE_RC5_SZ, "rc-5-sz" }, + { RC_TYPE_MCE_KBD, "mce_kbd" }, { RC_TYPE_LIRC, "lirc" }, { RC_TYPE_OTHER, "other" }, }; @@ -1099,7 +1100,6 @@ int rc_register_device(struct rc_dev *dev) if (rc < 0) goto out_input; } - mutex_unlock(&dev->lock); if (dev->change_protocol) { rc = dev->change_protocol(dev, rc_map->rc_type); @@ -1107,6 +1107,8 @@ int rc_register_device(struct rc_dev *dev) goto out_raw; } + mutex_unlock(&dev->lock); + IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n", dev->devno, dev->driver_name ? dev->driver_name : "unknown", diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 5147767ccb78045523bbd7f37dd732063a86c388..a166044779174bd4349572a052af3b16ff3b3c6d 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -205,6 +205,7 @@ struct redrat3_dev { /* rx signal timeout timer */ struct timer_list rx_timeout; + u32 hw_timeout; /* Is the device currently receiving? */ bool recv_in_progress; @@ -414,20 +415,10 @@ static u32 redrat3_us_to_len(u32 microsec) } -/* timer callback to send long trailing space on receive timeout */ +/* timer callback to send reset event */ static void redrat3_rx_timeout(unsigned long data) { struct redrat3_dev *rr3 = (struct redrat3_dev *)data; - DEFINE_IR_RAW_EVENT(rawir); - - rawir.pulse = false; - rawir.duration = rr3->rc->timeout; - rr3_dbg(rr3->dev, "storing trailing space with duration %d\n", - rawir.duration); - ir_raw_event_store_with_filter(rr3->rc, &rawir); - - rr3_dbg(rr3->dev, "calling ir_raw_event_handle\n"); - ir_raw_event_handle(rr3->rc); rr3_dbg(rr3->dev, "calling ir_raw_event_reset\n"); ir_raw_event_reset(rr3->rc); @@ -438,7 +429,7 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) DEFINE_IR_RAW_EVENT(rawir); struct redrat3_signal_header header; struct device *dev; - int i; + int i, trailer = 0; unsigned long delay; u32 mod_freq, single_len; u16 *len_vals; @@ -464,7 +455,8 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) if (!(header.length >= RR3_HEADER_LENGTH)) dev_warn(dev, "read returned less than rr3 header len\n"); - delay = usecs_to_jiffies(rr3->rc->timeout / 1000); + /* Make sure we reset the IR kfifo after a bit of inactivity */ + delay = usecs_to_jiffies(rr3->hw_timeout); mod_timer(&rr3->rx_timeout, jiffies + delay); memcpy(&tmp32, sig_data + RR3_PAUSE_OFFSET, sizeof(tmp32)); @@ -506,9 +498,6 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) u16 val = len_vals[data_vals[i]]; single_len = redrat3_len_to_us((u32)be16_to_cpu(val)); - /* cap the value to IR_MAX_DURATION */ - single_len &= IR_MAX_DURATION; - /* we should always get pulse/space/pulse/space samples */ if (i % 2) rawir.pulse = false; @@ -516,6 +505,12 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) rawir.pulse = true; rawir.duration = US_TO_NS(single_len); + /* Save initial pulse length to fudge trailer */ + if (i == 0) + trailer = rawir.duration; + /* cap the value to IR_MAX_DURATION */ + rawir.duration &= IR_MAX_DURATION; + rr3_dbg(dev, "storing %s with duration %d (i: %d)\n", rawir.pulse ? "pulse" : "space", rawir.duration, i); ir_raw_event_store_with_filter(rr3->rc, &rawir); @@ -525,7 +520,10 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) if (i % 2) { rawir.pulse = false; /* this duration is made up, and may not be ideal... */ - rawir.duration = rr3->rc->timeout / 2; + if (trailer < US_TO_NS(1000)) + rawir.duration = US_TO_NS(2800); + else + rawir.duration = trailer; rr3_dbg(dev, "storing trailing space with duration %d\n", rawir.duration); ir_raw_event_store_with_filter(rr3->rc, &rawir); @@ -629,36 +627,31 @@ static inline void redrat3_delete(struct redrat3_dev *rr3, kfree(rr3); } -static u32 redrat3_get_timeout(struct device *dev, - struct rc_dev *rc, struct usb_device *udev) +static u32 redrat3_get_timeout(struct redrat3_dev *rr3) { u32 *tmp; - u32 timeout = MS_TO_NS(150); /* a sane default, if things go haywire */ + u32 timeout = MS_TO_US(150); /* a sane default, if things go haywire */ int len, ret, pipe; len = sizeof(*tmp); tmp = kzalloc(len, GFP_KERNEL); if (!tmp) { - dev_warn(dev, "Memory allocation faillure\n"); + dev_warn(rr3->dev, "Memory allocation faillure\n"); return timeout; } - pipe = usb_rcvctrlpipe(udev, 0); - ret = usb_control_msg(udev, pipe, RR3_GET_IR_PARAM, + pipe = usb_rcvctrlpipe(rr3->udev, 0); + ret = usb_control_msg(rr3->udev, pipe, RR3_GET_IR_PARAM, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, RR3_IR_IO_SIG_TIMEOUT, 0, tmp, len, HZ * 5); if (ret != len) { - dev_warn(dev, "Failed to read timeout from hardware\n"); + dev_warn(rr3->dev, "Failed to read timeout from hardware\n"); return timeout; } - timeout = US_TO_NS(redrat3_len_to_us(be32_to_cpu(*tmp))); - if (timeout < rc->min_timeout) - timeout = rc->min_timeout; - else if (timeout > rc->max_timeout) - timeout = rc->max_timeout; + timeout = redrat3_len_to_us(be32_to_cpu(*tmp)); - rr3_dbg(dev, "Got timeout of %d ms\n", timeout / (1000 * 1000)); + rr3_dbg(rr3->dev, "Got timeout of %d ms\n", timeout / 1000); return timeout; } @@ -1110,9 +1103,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) rc->priv = rr3; rc->driver_type = RC_DRIVER_IR_RAW; rc->allowed_protos = RC_TYPE_ALL; - rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT); - rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT); - rc->timeout = redrat3_get_timeout(dev, rc, rr3->udev); + rc->timeout = US_TO_NS(2750); rc->tx_ir = redrat3_transmit_ir; rc->s_tx_carrier = redrat3_set_tx_carrier; rc->driver_name = DRIVER_NAME; @@ -1186,7 +1177,7 @@ static int __devinit redrat3_dev_probe(struct usb_interface *intf, rr3 = kzalloc(sizeof(*rr3), GFP_KERNEL); if (rr3 == NULL) { dev_err(dev, "Memory allocation failure\n"); - goto error; + goto no_endpoints; } rr3->dev = &intf->dev; @@ -1242,6 +1233,9 @@ static int __devinit redrat3_dev_probe(struct usb_interface *intf, if (retval < 0) goto error; + /* store current hardware timeout, in us, will use for kfifo resets */ + rr3->hw_timeout = redrat3_get_timeout(rr3); + /* default.. will get overridden by any sends with a freq defined */ rr3->carrier = 38000; @@ -1280,6 +1274,7 @@ static void __devexit redrat3_dev_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); rc_unregister_device(rr3->rc); + del_timer_sync(&rr3->rx_timeout); redrat3_delete(rr3, udev); rr3_ftr(&intf->dev, "RedRat3 IR Transceiver now disconnected\n"); diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 5d06b899e85959a97e75fea8478b74897f36a0ef..bec8abc965f78061e7238bad7eda1adf58bd8b92 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -6,8 +6,8 @@ * could probably support others (Winbond WEC102X, NatSemi, etc) * with minor modifications. * - * Original Author: David Härdeman - * Copyright (C) 2009 - 2010 David Härdeman + * Original Author: David Härdeman + * Copyright (C) 2009 - 2011 David Härdeman * * Dedicated to my daughter Matilda, without whose loving attention this * driver would have been finished in half the time and with a fraction @@ -577,16 +577,12 @@ wbcir_txmask(struct rc_dev *dev, u32 mask) } static int -wbcir_tx(struct rc_dev *dev, int *buf, u32 bufsize) +wbcir_tx(struct rc_dev *dev, unsigned *buf, unsigned count) { struct wbcir_data *data = dev->priv; - u32 count; unsigned i; unsigned long flags; - /* bufsize has been sanity checked by the caller */ - count = bufsize / sizeof(int); - /* Not sure if this is possible, but better safe than sorry */ spin_lock_irqsave(&data->spinlock, flags); if (data->txstate != WBCIR_TXSTATE_INACTIVE) { @@ -876,18 +872,8 @@ wbcir_init_hw(struct wbcir_data *data) /* prescaler 1.0, tx/rx fifo lvl 16 */ outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2); - /* Set baud divisor to generate one byte per bit/cell */ - switch (protocol) { - case IR_PROTOCOL_RC5: - outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL); - break; - case IR_PROTOCOL_RC6: - outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL); - break; - case IR_PROTOCOL_NEC: - outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL); - break; - } + /* Set baud divisor to sample every 10 us */ + outb(0x0F, data->sbase + WBCIR_REG_SP3_BGDL); outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH); /* Set CEIR mode */ @@ -896,9 +882,9 @@ wbcir_init_hw(struct wbcir_data *data) inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */ inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */ - /* Disable RX demod, run-length encoding/decoding, set freq span */ + /* Disable RX demod, enable run-length enc/dec, set freq span */ wbcir_select_bank(data, WBCIR_BANK_7); - outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG); + outb(0x90, data->sbase + WBCIR_REG_SP3_RCCFG); /* Disable timer */ wbcir_select_bank(data, WBCIR_BANK_4); diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index bb53de7fe4087b227f98b63cdc15b035d28f008c..f574dc012cad047a817201b00676ff1497ac255c 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -489,6 +489,15 @@ config VIDEO_TCM825X This is a driver for the Toshiba TCM825x VGA camera sensor. It is used for example in Nokia N800. +comment "Flash devices" + +config VIDEO_ADP1653 + tristate "ADP1653 flash support" + depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + ---help--- + This is a driver for the ADP1653 flash controller. It is used for + example in Nokia N900. + comment "Video improvement chips" config VIDEO_UPD64031A @@ -707,6 +716,8 @@ source "drivers/media/video/cx18/Kconfig" source "drivers/media/video/saa7164/Kconfig" +source "drivers/media/video/marvell-ccic/Kconfig" + config VIDEO_M32R_AR tristate "AR devices" depends on M32R && VIDEO_V4L2 @@ -726,15 +737,6 @@ config VIDEO_M32R_AR_M64278 To compile this driver as a module, choose M here: the module will be called arv. -config VIDEO_CAFE_CCIC - tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support" - depends on PCI && I2C && VIDEO_V4L2 - select VIDEO_OV7670 - ---help--- - This is a video4linux2 driver for the Marvell 88ALP01 integrated - CMOS camera controller. This is the controller found on first- - generation OLPC systems. - config VIDEO_SR030PC30 tristate "SR030PC30 VGA camera sensor support" depends on I2C && VIDEO_V4L2 @@ -846,6 +848,12 @@ config SOC_CAMERA_OV2640 help This is a ov2640 camera driver +config SOC_CAMERA_OV5642 + tristate "ov5642 camera support" + depends on SOC_CAMERA && I2C + help + This is a V4L2 camera driver for the OmniVision OV5642 sensor + config SOC_CAMERA_OV6650 tristate "ov6650 sensor support" depends on SOC_CAMERA && I2C @@ -952,6 +960,14 @@ config VIDEO_SAMSUNG_S5P_FIMC To compile this driver as a module, choose M here: the module will be called s5p-fimc. +config VIDEO_ATMEL_ISI + tristate "ATMEL Image Sensor Interface (ISI) support" + depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91 + select VIDEOBUF2_DMA_CONTIG + ---help--- + This module makes the ATMEL Image Sensor Interface available + as a v4l2 device. + config VIDEO_S5P_MIPI_CSIS tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver" depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P && VIDEO_V4L2_SUBDEV_API @@ -961,6 +977,8 @@ config VIDEO_S5P_MIPI_CSIS To compile this driver as a module, choose M here: the module will be called s5p-csis. +source "drivers/media/video/s5p-tv/Kconfig" + # # USB Multimedia device configuration # @@ -1056,4 +1074,12 @@ config VIDEO_MEM2MEM_TESTDEV framework. +config VIDEO_SAMSUNG_S5P_MFC + tristate "Samsung S5P MFC 5.1 Video Codec" + depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P + select VIDEOBUF2_DMA_CONTIG + default n + help + MFC 5.1 driver for V4L2. + endif # V4L_MEM2MEM_DRIVERS diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index f0fecd6f6a33e818c4f4713d2b62e1ecd762e4a9..272390072aef7142b5e419e4443d7a5a3927533f 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ +obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o @@ -78,6 +79,7 @@ obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o +obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o @@ -127,7 +129,8 @@ obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o -obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o +obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/ +obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/ obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o @@ -166,8 +169,11 @@ obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o +obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV) += s5p-tv/ obj-$(CONFIG_ARCH_DAVINCI) += davinci/ diff --git a/drivers/media/video/adp1653.c b/drivers/media/video/adp1653.c new file mode 100644 index 0000000000000000000000000000000000000000..be7befd60947eff952698fc36f14923381ad69b7 --- /dev/null +++ b/drivers/media/video/adp1653.c @@ -0,0 +1,491 @@ +/* + * drivers/media/video/adp1653.c + * + * Copyright (C) 2008--2011 Nokia Corporation + * + * Contact: Sakari Ailus + * + * Contributors: + * Sakari Ailus + * Tuukka Toivonen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * TODO: + * - fault interrupt handling + * - hardware strobe + * - power doesn't need to be ON if all lights are off + * + */ + +#include +#include +#include +#include +#include +#include + +#define TIMEOUT_MAX 820000 +#define TIMEOUT_STEP 54600 +#define TIMEOUT_MIN (TIMEOUT_MAX - ADP1653_REG_CONFIG_TMR_SET_MAX \ + * TIMEOUT_STEP) +#define TIMEOUT_US_TO_CODE(t) ((TIMEOUT_MAX + (TIMEOUT_STEP / 2) - (t)) \ + / TIMEOUT_STEP) +#define TIMEOUT_CODE_TO_US(c) (TIMEOUT_MAX - (c) * TIMEOUT_STEP) + +/* Write values into ADP1653 registers. */ +static int adp1653_update_hw(struct adp1653_flash *flash) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); + u8 out_sel; + u8 config = 0; + int rval; + + out_sel = ADP1653_INDICATOR_INTENSITY_uA_TO_REG( + flash->indicator_intensity->val) + << ADP1653_REG_OUT_SEL_ILED_SHIFT; + + switch (flash->led_mode->val) { + case V4L2_FLASH_LED_MODE_NONE: + break; + case V4L2_FLASH_LED_MODE_FLASH: + /* Flash mode, light on with strobe, duration from timer */ + config = ADP1653_REG_CONFIG_TMR_CFG; + config |= TIMEOUT_US_TO_CODE(flash->flash_timeout->val) + << ADP1653_REG_CONFIG_TMR_SET_SHIFT; + break; + case V4L2_FLASH_LED_MODE_TORCH: + /* Torch mode, light immediately on, duration indefinite */ + out_sel |= ADP1653_FLASH_INTENSITY_mA_TO_REG( + flash->torch_intensity->val) + << ADP1653_REG_OUT_SEL_HPLED_SHIFT; + break; + } + + rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, out_sel); + if (rval < 0) + return rval; + + rval = i2c_smbus_write_byte_data(client, ADP1653_REG_CONFIG, config); + if (rval < 0) + return rval; + + return 0; +} + +static int adp1653_get_fault(struct adp1653_flash *flash) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); + int fault; + int rval; + + fault = i2c_smbus_read_byte_data(client, ADP1653_REG_FAULT); + if (IS_ERR_VALUE(fault)) + return fault; + + flash->fault |= fault; + + if (!flash->fault) + return 0; + + /* Clear faults. */ + rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, 0); + if (IS_ERR_VALUE(rval)) + return rval; + + flash->led_mode->val = V4L2_FLASH_LED_MODE_NONE; + + rval = adp1653_update_hw(flash); + if (IS_ERR_VALUE(rval)) + return rval; + + return flash->fault; +} + +static int adp1653_strobe(struct adp1653_flash *flash, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); + u8 out_sel = ADP1653_INDICATOR_INTENSITY_uA_TO_REG( + flash->indicator_intensity->val) + << ADP1653_REG_OUT_SEL_ILED_SHIFT; + int rval; + + if (flash->led_mode->val != V4L2_FLASH_LED_MODE_FLASH) + return -EBUSY; + + if (!enable) + return i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, + out_sel); + + out_sel |= ADP1653_FLASH_INTENSITY_mA_TO_REG( + flash->flash_intensity->val) + << ADP1653_REG_OUT_SEL_HPLED_SHIFT; + rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, out_sel); + if (rval) + return rval; + + /* Software strobe using i2c */ + rval = i2c_smbus_write_byte_data(client, ADP1653_REG_SW_STROBE, + ADP1653_REG_SW_STROBE_SW_STROBE); + if (rval) + return rval; + return i2c_smbus_write_byte_data(client, ADP1653_REG_SW_STROBE, 0); +} + +/* -------------------------------------------------------------------------- + * V4L2 controls + */ + +static int adp1653_get_ctrl(struct v4l2_ctrl *ctrl) +{ + struct adp1653_flash *flash = + container_of(ctrl->handler, struct adp1653_flash, ctrls); + int rval; + + rval = adp1653_get_fault(flash); + if (IS_ERR_VALUE(rval)) + return rval; + + ctrl->cur.val = 0; + + if (flash->fault & ADP1653_REG_FAULT_FLT_SCP) + ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT; + if (flash->fault & ADP1653_REG_FAULT_FLT_OT) + ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE; + if (flash->fault & ADP1653_REG_FAULT_FLT_TMR) + ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT; + if (flash->fault & ADP1653_REG_FAULT_FLT_OV) + ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE; + + flash->fault = 0; + + return 0; +} + +static int adp1653_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct adp1653_flash *flash = + container_of(ctrl->handler, struct adp1653_flash, ctrls); + int rval; + + rval = adp1653_get_fault(flash); + if (IS_ERR_VALUE(rval)) + return rval; + if ((rval & (ADP1653_REG_FAULT_FLT_SCP | + ADP1653_REG_FAULT_FLT_OT | + ADP1653_REG_FAULT_FLT_OV)) && + (ctrl->id == V4L2_CID_FLASH_STROBE || + ctrl->id == V4L2_CID_FLASH_TORCH_INTENSITY || + ctrl->id == V4L2_CID_FLASH_LED_MODE)) + return -EBUSY; + + switch (ctrl->id) { + case V4L2_CID_FLASH_STROBE: + return adp1653_strobe(flash, 1); + case V4L2_CID_FLASH_STROBE_STOP: + return adp1653_strobe(flash, 0); + } + + return adp1653_update_hw(flash); +} + +static const struct v4l2_ctrl_ops adp1653_ctrl_ops = { + .g_volatile_ctrl = adp1653_get_ctrl, + .s_ctrl = adp1653_set_ctrl, +}; + +static int adp1653_init_controls(struct adp1653_flash *flash) +{ + struct v4l2_ctrl *fault; + + v4l2_ctrl_handler_init(&flash->ctrls, 9); + + flash->led_mode = + v4l2_ctrl_new_std_menu(&flash->ctrls, &adp1653_ctrl_ops, + V4L2_CID_FLASH_LED_MODE, + V4L2_FLASH_LED_MODE_TORCH, ~0x7, 0); + v4l2_ctrl_new_std_menu(&flash->ctrls, &adp1653_ctrl_ops, + V4L2_CID_FLASH_STROBE_SOURCE, + V4L2_FLASH_STROBE_SOURCE_SOFTWARE, ~0x1, 0); + v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops, + V4L2_CID_FLASH_STROBE, 0, 0, 0, 0); + v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops, + V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0); + flash->flash_timeout = + v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops, + V4L2_CID_FLASH_TIMEOUT, TIMEOUT_MIN, + flash->platform_data->max_flash_timeout, + TIMEOUT_STEP, + flash->platform_data->max_flash_timeout); + flash->flash_intensity = + v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops, + V4L2_CID_FLASH_INTENSITY, + ADP1653_FLASH_INTENSITY_MIN, + flash->platform_data->max_flash_intensity, + 1, flash->platform_data->max_flash_intensity); + flash->torch_intensity = + v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops, + V4L2_CID_FLASH_TORCH_INTENSITY, + ADP1653_TORCH_INTENSITY_MIN, + flash->platform_data->max_torch_intensity, + ADP1653_FLASH_INTENSITY_STEP, + flash->platform_data->max_torch_intensity); + flash->indicator_intensity = + v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops, + V4L2_CID_FLASH_INDICATOR_INTENSITY, + ADP1653_INDICATOR_INTENSITY_MIN, + flash->platform_data->max_indicator_intensity, + ADP1653_INDICATOR_INTENSITY_STEP, + ADP1653_INDICATOR_INTENSITY_MIN); + fault = v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops, + V4L2_CID_FLASH_FAULT, 0, + V4L2_FLASH_FAULT_OVER_VOLTAGE + | V4L2_FLASH_FAULT_OVER_TEMPERATURE + | V4L2_FLASH_FAULT_SHORT_CIRCUIT, 0, 0); + + if (flash->ctrls.error) + return flash->ctrls.error; + + fault->is_volatile = 1; + + flash->subdev.ctrl_handler = &flash->ctrls; + return 0; +} + +/* -------------------------------------------------------------------------- + * V4L2 subdev operations + */ + +static int +adp1653_init_device(struct adp1653_flash *flash) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); + int rval; + + /* Clear FAULT register by writing zero to OUT_SEL */ + rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, 0); + if (rval < 0) { + dev_err(&client->dev, "failed writing fault register\n"); + return -EIO; + } + + mutex_lock(&flash->ctrls.lock); + /* Reset faults before reading new ones. */ + flash->fault = 0; + rval = adp1653_get_fault(flash); + mutex_unlock(&flash->ctrls.lock); + if (rval > 0) { + dev_err(&client->dev, "faults detected: 0x%1.1x\n", rval); + return -EIO; + } + + mutex_lock(&flash->ctrls.lock); + rval = adp1653_update_hw(flash); + mutex_unlock(&flash->ctrls.lock); + if (rval) { + dev_err(&client->dev, + "adp1653_update_hw failed at %s\n", __func__); + return -EIO; + } + + return 0; +} + +static int +__adp1653_set_power(struct adp1653_flash *flash, int on) +{ + int ret; + + ret = flash->platform_data->power(&flash->subdev, on); + if (ret < 0) + return ret; + + if (!on) + return 0; + + ret = adp1653_init_device(flash); + if (ret < 0) + flash->platform_data->power(&flash->subdev, 0); + + return ret; +} + +static int +adp1653_set_power(struct v4l2_subdev *subdev, int on) +{ + struct adp1653_flash *flash = to_adp1653_flash(subdev); + int ret = 0; + + mutex_lock(&flash->power_lock); + + /* If the power count is modified from 0 to != 0 or from != 0 to 0, + * update the power state. + */ + if (flash->power_count == !on) { + ret = __adp1653_set_power(flash, !!on); + if (ret < 0) + goto done; + } + + /* Update the power count. */ + flash->power_count += on ? 1 : -1; + WARN_ON(flash->power_count < 0); + +done: + mutex_unlock(&flash->power_lock); + return ret; +} + +static int adp1653_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return adp1653_set_power(sd, 1); +} + +static int adp1653_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return adp1653_set_power(sd, 0); +} + +static const struct v4l2_subdev_core_ops adp1653_core_ops = { + .s_power = adp1653_set_power, +}; + +static const struct v4l2_subdev_ops adp1653_ops = { + .core = &adp1653_core_ops, +}; + +static const struct v4l2_subdev_internal_ops adp1653_internal_ops = { + .open = adp1653_open, + .close = adp1653_close, +}; + +/* -------------------------------------------------------------------------- + * I2C driver + */ +#ifdef CONFIG_PM + +static int adp1653_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct adp1653_flash *flash = to_adp1653_flash(subdev); + + if (!flash->power_count) + return 0; + + return __adp1653_set_power(flash, 0); +} + +static int adp1653_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct adp1653_flash *flash = to_adp1653_flash(subdev); + + if (!flash->power_count) + return 0; + + return __adp1653_set_power(flash, 1); +} + +#else + +#define adp1653_suspend NULL +#define adp1653_resume NULL + +#endif /* CONFIG_PM */ + +static int adp1653_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct adp1653_flash *flash; + int ret; + + flash = kzalloc(sizeof(*flash), GFP_KERNEL); + if (flash == NULL) + return -ENOMEM; + + flash->platform_data = client->dev.platform_data; + + mutex_init(&flash->power_lock); + + v4l2_i2c_subdev_init(&flash->subdev, client, &adp1653_ops); + flash->subdev.internal_ops = &adp1653_internal_ops; + flash->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + adp1653_init_controls(flash); + + ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0); + if (ret < 0) + kfree(flash); + + return ret; +} + +static int __exit adp1653_remove(struct i2c_client *client) +{ + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct adp1653_flash *flash = to_adp1653_flash(subdev); + + v4l2_device_unregister_subdev(&flash->subdev); + v4l2_ctrl_handler_free(&flash->ctrls); + media_entity_cleanup(&flash->subdev.entity); + kfree(flash); + return 0; +} + +static const struct i2c_device_id adp1653_id_table[] = { + { ADP1653_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adp1653_id_table); + +static struct dev_pm_ops adp1653_pm_ops = { + .suspend = adp1653_suspend, + .resume = adp1653_resume, +}; + +static struct i2c_driver adp1653_i2c_driver = { + .driver = { + .name = ADP1653_NAME, + .pm = &adp1653_pm_ops, + }, + .probe = adp1653_probe, + .remove = __exit_p(adp1653_remove), + .id_table = adp1653_id_table, +}; + +static int __init adp1653_init(void) +{ + int rval; + + rval = i2c_add_driver(&adp1653_i2c_driver); + if (rval) + printk(KERN_ALERT "%s: failed at i2c_add_driver\n", __func__); + + return rval; +} + +static void __exit adp1653_exit(void) +{ + i2c_del_driver(&adp1653_i2c_driver); +} + +module_init(adp1653_init); +module_exit(adp1653_exit); + +MODULE_AUTHOR("Sakari Ailus "); +MODULE_DESCRIPTION("Analog Devices ADP1653 LED flash driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index f989f2820d88e90f49f5b4fc6081002126c0c3c2..b6ed44aebe30bcf1c186bd877125bca353e6bb96 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -54,7 +53,7 @@ */ #define USE_INT 0 /* Don't modify */ -#define VERSION "0.04" +#define VERSION "0.0.5" #define ar_inl(addr) inl((unsigned long)(addr)) #define ar_outl(val, addr) outl((unsigned long)(val), (unsigned long)(addr)) @@ -404,7 +403,6 @@ static int ar_querycap(struct file *file, void *priv, strlcpy(vcap->driver, ar->vdev.name, sizeof(vcap->driver)); strlcpy(vcap->card, "Colour AR VGA", sizeof(vcap->card)); strlcpy(vcap->bus_info, "Platform", sizeof(vcap->bus_info)); - vcap->version = KERNEL_VERSION(0, 0, 4); vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; return 0; } @@ -879,3 +877,4 @@ module_exit(ar_cleanup_module); MODULE_AUTHOR("Takeo Takahashi "); MODULE_DESCRIPTION("Colour AR M64278(VGA) for Video4Linux"); MODULE_LICENSE("GPL"); +MODULE_VERSION(VERSION); diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c new file mode 100644 index 0000000000000000000000000000000000000000..7b89f00501b827efc52aee371eede35ef5d37b31 --- /dev/null +++ b/drivers/media/video/atmel-isi.c @@ -0,0 +1,1048 @@ +/* + * Copyright (c) 2011 Atmel Corporation + * Josh Wu, + * + * Based on previous work by Lars Haring, + * and Sedji Gaouaou + * Based on the bttv driver for Bt848 with respective copyright holders + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MAX_BUFFER_NUM 32 +#define MAX_SUPPORT_WIDTH 2048 +#define MAX_SUPPORT_HEIGHT 2048 +#define VID_LIMIT_BYTES (16 * 1024 * 1024) +#define MIN_FRAME_RATE 15 +#define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE) + +/* ISI states */ +enum { + ISI_STATE_IDLE = 0, + ISI_STATE_READY, + ISI_STATE_WAIT_SOF, +}; + +/* Frame buffer descriptor */ +struct fbd { + /* Physical address of the frame buffer */ + u32 fb_address; + /* DMA Control Register(only in HISI2) */ + u32 dma_ctrl; + /* Physical address of the next fbd */ + u32 next_fbd_address; +}; + +static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl) +{ + fb_desc->dma_ctrl = ctrl; +} + +struct isi_dma_desc { + struct list_head list; + struct fbd *p_fbd; + u32 fbd_phys; +}; + +/* Frame buffer data */ +struct frame_buffer { + struct vb2_buffer vb; + struct isi_dma_desc *p_dma_desc; + struct list_head list; +}; + +struct atmel_isi { + /* Protects the access of variables shared with the ISR */ + spinlock_t lock; + void __iomem *regs; + + int sequence; + /* State of the ISI module in capturing mode */ + int state; + + /* Wait queue for waiting for SOF */ + wait_queue_head_t vsync_wq; + + struct vb2_alloc_ctx *alloc_ctx; + + /* Allocate descriptors for dma buffer use */ + struct fbd *p_fb_descriptors; + u32 fb_descriptors_phys; + struct list_head dma_desc_head; + struct isi_dma_desc dma_desc[MAX_BUFFER_NUM]; + + struct completion complete; + struct clk *pclk; + unsigned int irq; + + struct isi_platform_data *pdata; + + struct list_head video_buffer_list; + struct frame_buffer *active; + + struct soc_camera_device *icd; + struct soc_camera_host soc_host; +}; + +static void isi_writel(struct atmel_isi *isi, u32 reg, u32 val) +{ + writel(val, isi->regs + reg); +} +static u32 isi_readl(struct atmel_isi *isi, u32 reg) +{ + return readl(isi->regs + reg); +} + +static int configure_geometry(struct atmel_isi *isi, u32 width, + u32 height, enum v4l2_mbus_pixelcode code) +{ + u32 cfg2, cr; + + switch (code) { + /* YUV, including grey */ + case V4L2_MBUS_FMT_Y8_1X8: + cr = ISI_CFG2_GRAYSCALE; + break; + case V4L2_MBUS_FMT_UYVY8_2X8: + cr = ISI_CFG2_YCC_SWAP_MODE_3; + break; + case V4L2_MBUS_FMT_VYUY8_2X8: + cr = ISI_CFG2_YCC_SWAP_MODE_2; + break; + case V4L2_MBUS_FMT_YUYV8_2X8: + cr = ISI_CFG2_YCC_SWAP_MODE_1; + break; + case V4L2_MBUS_FMT_YVYU8_2X8: + cr = ISI_CFG2_YCC_SWAP_DEFAULT; + break; + /* RGB, TODO */ + default: + return -EINVAL; + } + + isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); + + cfg2 = isi_readl(isi, ISI_CFG2); + cfg2 |= cr; + /* Set width */ + cfg2 &= ~(ISI_CFG2_IM_HSIZE_MASK); + cfg2 |= ((width - 1) << ISI_CFG2_IM_HSIZE_OFFSET) & + ISI_CFG2_IM_HSIZE_MASK; + /* Set height */ + cfg2 &= ~(ISI_CFG2_IM_VSIZE_MASK); + cfg2 |= ((height - 1) << ISI_CFG2_IM_VSIZE_OFFSET) + & ISI_CFG2_IM_VSIZE_MASK; + isi_writel(isi, ISI_CFG2, cfg2); + + return 0; +} + +static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi) +{ + if (isi->active) { + struct vb2_buffer *vb = &isi->active->vb; + struct frame_buffer *buf = isi->active; + + list_del_init(&buf->list); + do_gettimeofday(&vb->v4l2_buf.timestamp); + vb->v4l2_buf.sequence = isi->sequence++; + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + } + + if (list_empty(&isi->video_buffer_list)) { + isi->active = NULL; + } else { + /* start next dma frame. */ + isi->active = list_entry(isi->video_buffer_list.next, + struct frame_buffer, list); + isi_writel(isi, ISI_DMA_C_DSCR, + isi->active->p_dma_desc->fbd_phys); + isi_writel(isi, ISI_DMA_C_CTRL, + ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); + isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); + } + return IRQ_HANDLED; +} + +/* ISI interrupt service routine */ +static irqreturn_t isi_interrupt(int irq, void *dev_id) +{ + struct atmel_isi *isi = dev_id; + u32 status, mask, pending; + irqreturn_t ret = IRQ_NONE; + + spin_lock(&isi->lock); + + status = isi_readl(isi, ISI_STATUS); + mask = isi_readl(isi, ISI_INTMASK); + pending = status & mask; + + if (pending & ISI_CTRL_SRST) { + complete(&isi->complete); + isi_writel(isi, ISI_INTDIS, ISI_CTRL_SRST); + ret = IRQ_HANDLED; + } else if (pending & ISI_CTRL_DIS) { + complete(&isi->complete); + isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS); + ret = IRQ_HANDLED; + } else { + if ((pending & ISI_SR_VSYNC) && + (isi->state == ISI_STATE_IDLE)) { + isi->state = ISI_STATE_READY; + wake_up_interruptible(&isi->vsync_wq); + ret = IRQ_HANDLED; + } + if (likely(pending & ISI_SR_CXFR_DONE)) + ret = atmel_isi_handle_streaming(isi); + } + + spin_unlock(&isi->lock); + return ret; +} + +#define WAIT_ISI_RESET 1 +#define WAIT_ISI_DISABLE 0 +static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) +{ + unsigned long timeout; + /* + * The reset or disable will only succeed if we have a + * pixel clock from the camera. + */ + init_completion(&isi->complete); + + if (wait_reset) { + isi_writel(isi, ISI_INTEN, ISI_CTRL_SRST); + isi_writel(isi, ISI_CTRL, ISI_CTRL_SRST); + } else { + isi_writel(isi, ISI_INTEN, ISI_CTRL_DIS); + isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); + } + + timeout = wait_for_completion_timeout(&isi->complete, + msecs_to_jiffies(100)); + if (timeout == 0) + return -ETIMEDOUT; + + return 0; +} + +/* ------------------------------------------------------------------ + Videobuf operations + ------------------------------------------------------------------*/ +static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned long sizes[], + void *alloc_ctxs[]) +{ + struct soc_camera_device *icd = soc_camera_from_vb2q(vq); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct atmel_isi *isi = ici->priv; + unsigned long size; + int ret, bytes_per_line; + + /* Reset ISI */ + ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET); + if (ret < 0) { + dev_err(icd->parent, "Reset ISI timed out\n"); + return ret; + } + /* Disable all interrupts */ + isi_writel(isi, ISI_INTDIS, ~0UL); + + bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + if (bytes_per_line < 0) + return bytes_per_line; + + size = bytes_per_line * icd->user_height; + + if (!*nbuffers || *nbuffers > MAX_BUFFER_NUM) + *nbuffers = MAX_BUFFER_NUM; + + if (size * *nbuffers > VID_LIMIT_BYTES) + *nbuffers = VID_LIMIT_BYTES / size; + + *nplanes = 1; + sizes[0] = size; + alloc_ctxs[0] = isi->alloc_ctx; + + isi->sequence = 0; + isi->active = NULL; + + dev_dbg(icd->parent, "%s, count=%d, size=%ld\n", __func__, + *nbuffers, size); + + return 0; +} + +static int buffer_init(struct vb2_buffer *vb) +{ + struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb); + + buf->p_dma_desc = NULL; + INIT_LIST_HEAD(&buf->list); + + return 0; +} + +static int buffer_prepare(struct vb2_buffer *vb) +{ + struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); + struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct atmel_isi *isi = ici->priv; + unsigned long size; + struct isi_dma_desc *desc; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + if (bytes_per_line < 0) + return bytes_per_line; + + size = bytes_per_line * icd->user_height; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(icd->parent, "%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(&buf->vb, 0, size); + + if (!buf->p_dma_desc) { + if (list_empty(&isi->dma_desc_head)) { + dev_err(icd->parent, "Not enough dma descriptors.\n"); + return -EINVAL; + } else { + /* Get an available descriptor */ + desc = list_entry(isi->dma_desc_head.next, + struct isi_dma_desc, list); + /* Delete the descriptor since now it is used */ + list_del_init(&desc->list); + + /* Initialize the dma descriptor */ + desc->p_fbd->fb_address = + vb2_dma_contig_plane_paddr(vb, 0); + desc->p_fbd->next_fbd_address = 0; + set_dma_ctrl(desc->p_fbd, ISI_DMA_CTRL_WB); + + buf->p_dma_desc = desc; + } + } + return 0; +} + +static void buffer_cleanup(struct vb2_buffer *vb) +{ + struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct atmel_isi *isi = ici->priv; + struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb); + + /* This descriptor is available now and we add to head list */ + if (buf->p_dma_desc) + list_add(&buf->p_dma_desc->list, &isi->dma_desc_head); +} + +static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer) +{ + u32 ctrl, cfg1; + + cfg1 = isi_readl(isi, ISI_CFG1); + /* Enable irq: cxfr for the codec path, pxfr for the preview path */ + isi_writel(isi, ISI_INTEN, + ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); + + /* Check if already in a frame */ + if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) { + dev_err(isi->icd->parent, "Already in frame handling.\n"); + return; + } + + isi_writel(isi, ISI_DMA_C_DSCR, buffer->p_dma_desc->fbd_phys); + isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); + isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); + + /* Enable linked list */ + cfg1 |= isi->pdata->frate | ISI_CFG1_DISCR; + + /* Enable codec path and ISI */ + ctrl = ISI_CTRL_CDC | ISI_CTRL_EN; + isi_writel(isi, ISI_CTRL, ctrl); + isi_writel(isi, ISI_CFG1, cfg1); +} + +static void buffer_queue(struct vb2_buffer *vb) +{ + struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct atmel_isi *isi = ici->priv; + struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb); + unsigned long flags = 0; + + spin_lock_irqsave(&isi->lock, flags); + list_add_tail(&buf->list, &isi->video_buffer_list); + + if (isi->active == NULL) { + isi->active = buf; + start_dma(isi, buf); + } + spin_unlock_irqrestore(&isi->lock, flags); +} + +static int start_streaming(struct vb2_queue *vq) +{ + struct soc_camera_device *icd = soc_camera_from_vb2q(vq); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct atmel_isi *isi = ici->priv; + + u32 sr = 0; + int ret; + + spin_lock_irq(&isi->lock); + isi->state = ISI_STATE_IDLE; + /* Clear any pending SOF interrupt */ + sr = isi_readl(isi, ISI_STATUS); + /* Enable VSYNC interrupt for SOF */ + isi_writel(isi, ISI_INTEN, ISI_SR_VSYNC); + isi_writel(isi, ISI_CTRL, ISI_CTRL_EN); + spin_unlock_irq(&isi->lock); + + dev_dbg(icd->parent, "Waiting for SOF\n"); + ret = wait_event_interruptible(isi->vsync_wq, + isi->state != ISI_STATE_IDLE); + if (ret) + return ret; + + if (isi->state != ISI_STATE_READY) + return -EIO; + + spin_lock_irq(&isi->lock); + isi->state = ISI_STATE_WAIT_SOF; + isi_writel(isi, ISI_INTDIS, ISI_SR_VSYNC); + spin_unlock_irq(&isi->lock); + + return 0; +} + +/* abort streaming and wait for last buffer */ +static int stop_streaming(struct vb2_queue *vq) +{ + struct soc_camera_device *icd = soc_camera_from_vb2q(vq); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct atmel_isi *isi = ici->priv; + struct frame_buffer *buf, *node; + int ret = 0; + unsigned long timeout; + + spin_lock_irq(&isi->lock); + isi->active = NULL; + /* Release all active buffers */ + list_for_each_entry_safe(buf, node, &isi->video_buffer_list, list) { + list_del_init(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irq(&isi->lock); + + timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; + /* Wait until the end of the current frame. */ + while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) && + time_before(jiffies, timeout)) + msleep(1); + + if (time_after(jiffies, timeout)) { + dev_err(icd->parent, + "Timeout waiting for finishing codec request\n"); + return -ETIMEDOUT; + } + + /* Disable interrupts */ + isi_writel(isi, ISI_INTDIS, + ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); + + /* Disable ISI and wait for it is done */ + ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE); + if (ret < 0) + dev_err(icd->parent, "Disable ISI timed out\n"); + + return ret; +} + +static struct vb2_ops isi_video_qops = { + .queue_setup = queue_setup, + .buf_init = buffer_init, + .buf_prepare = buffer_prepare, + .buf_cleanup = buffer_cleanup, + .buf_queue = buffer_queue, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, + .wait_prepare = soc_camera_unlock, + .wait_finish = soc_camera_lock, +}; + +/* ------------------------------------------------------------------ + SOC camera operations for the device + ------------------------------------------------------------------*/ +static int isi_camera_init_videobuf(struct vb2_queue *q, + struct soc_camera_device *icd) +{ + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP; + q->drv_priv = icd; + q->buf_struct_size = sizeof(struct frame_buffer); + q->ops = &isi_video_qops; + q->mem_ops = &vb2_dma_contig_memops; + + return vb2_queue_init(q); +} + +static int isi_camera_set_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct atmel_isi *isi = ici->priv; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + const struct soc_camera_format_xlate *xlate; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; + int ret; + + xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); + if (!xlate) { + dev_warn(icd->parent, "Format %x not found\n", + pix->pixelformat); + return -EINVAL; + } + + dev_dbg(icd->parent, "Plan to set format %dx%d\n", + pix->width, pix->height); + + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + if (ret < 0) + return ret; + + if (mf.code != xlate->code) + return -EINVAL; + + ret = configure_geometry(isi, pix->width, pix->height, xlate->code); + if (ret < 0) + return ret; + + pix->width = mf.width; + pix->height = mf.height; + pix->field = mf.field; + pix->colorspace = mf.colorspace; + icd->current_fmt = xlate; + + dev_dbg(icd->parent, "Finally set format %dx%d\n", + pix->width, pix->height); + + return ret; +} + +static int isi_camera_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + const struct soc_camera_format_xlate *xlate; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; + u32 pixfmt = pix->pixelformat; + int ret; + + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (pixfmt && !xlate) { + dev_warn(icd->parent, "Format %x not found\n", pixfmt); + return -EINVAL; + } + + /* limit to Atmel ISI hardware capabilities */ + if (pix->height > MAX_SUPPORT_HEIGHT) + pix->height = MAX_SUPPORT_HEIGHT; + if (pix->width > MAX_SUPPORT_WIDTH) + pix->width = MAX_SUPPORT_WIDTH; + + /* limit to sensor capabilities */ + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + + ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + if (ret < 0) + return ret; + + pix->width = mf.width; + pix->height = mf.height; + pix->colorspace = mf.colorspace; + + switch (mf.field) { + case V4L2_FIELD_ANY: + pix->field = V4L2_FIELD_NONE; + break; + case V4L2_FIELD_NONE: + break; + default: + dev_err(icd->parent, "Field type %d unsupported.\n", + mf.field); + ret = -EINVAL; + } + + return ret; +} + +static const struct soc_mbus_pixelfmt isi_camera_formats[] = { + { + .fourcc = V4L2_PIX_FMT_YUYV, + .name = "Packed YUV422 16 bit", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, + }, +}; + +/* This will be corrected as we get more formats */ +static bool isi_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) +{ + return fmt->packing == SOC_MBUS_PACKING_NONE || + (fmt->bits_per_sample == 8 && + fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || + (fmt->bits_per_sample > 8 && + fmt->packing == SOC_MBUS_PACKING_EXTEND16); +} + +static unsigned long make_bus_param(struct atmel_isi *isi) +{ + unsigned long flags; + /* + * Platform specified synchronization and pixel clock polarities are + * only a recommendation and are only used during probing. Atmel ISI + * camera interface only works in master mode, i.e., uses HSYNC and + * VSYNC signals from the sensor + */ + flags = SOCAM_MASTER | + SOCAM_HSYNC_ACTIVE_HIGH | + SOCAM_HSYNC_ACTIVE_LOW | + SOCAM_VSYNC_ACTIVE_HIGH | + SOCAM_VSYNC_ACTIVE_LOW | + SOCAM_PCLK_SAMPLE_RISING | + SOCAM_PCLK_SAMPLE_FALLING | + SOCAM_DATA_ACTIVE_HIGH; + + if (isi->pdata->data_width_flags & ISI_DATAWIDTH_10) + flags |= SOCAM_DATAWIDTH_10; + + if (isi->pdata->data_width_flags & ISI_DATAWIDTH_8) + flags |= SOCAM_DATAWIDTH_8; + + if (flags & SOCAM_DATAWIDTH_MASK) + return flags; + + return 0; +} + +static int isi_camera_try_bus_param(struct soc_camera_device *icd, + unsigned char buswidth) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct atmel_isi *isi = ici->priv; + unsigned long camera_flags; + int ret; + + camera_flags = icd->ops->query_bus_param(icd); + ret = soc_camera_bus_param_compatible(camera_flags, + make_bus_param(isi)); + if (!ret) + return -EINVAL; + return 0; +} + + +static int isi_camera_get_formats(struct soc_camera_device *icd, + unsigned int idx, + struct soc_camera_format_xlate *xlate) +{ + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + int formats = 0, ret; + /* sensor format */ + enum v4l2_mbus_pixelcode code; + /* soc camera host format */ + const struct soc_mbus_pixelfmt *fmt; + + ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + if (ret < 0) + /* No more formats */ + return 0; + + fmt = soc_mbus_get_fmtdesc(code); + if (!fmt) { + dev_err(icd->parent, + "Invalid format code #%u: %d\n", idx, code); + return 0; + } + + /* This also checks support for the requested bits-per-sample */ + ret = isi_camera_try_bus_param(icd, fmt->bits_per_sample); + if (ret < 0) { + dev_err(icd->parent, + "Fail to try the bus parameters.\n"); + return 0; + } + + switch (code) { + case V4L2_MBUS_FMT_UYVY8_2X8: + case V4L2_MBUS_FMT_VYUY8_2X8: + case V4L2_MBUS_FMT_YUYV8_2X8: + case V4L2_MBUS_FMT_YVYU8_2X8: + formats++; + if (xlate) { + xlate->host_fmt = &isi_camera_formats[0]; + xlate->code = code; + xlate++; + dev_dbg(icd->parent, "Providing format %s using code %d\n", + isi_camera_formats[0].name, code); + } + break; + default: + if (!isi_camera_packing_supported(fmt)) + return 0; + if (xlate) + dev_dbg(icd->parent, + "Providing format %s in pass-through mode\n", + fmt->name); + } + + /* Generic pass-through */ + formats++; + if (xlate) { + xlate->host_fmt = fmt; + xlate->code = code; + xlate++; + } + + return formats; +} + +/* Called with .video_lock held */ +static int isi_camera_add_device(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct atmel_isi *isi = ici->priv; + int ret; + + if (isi->icd) + return -EBUSY; + + ret = clk_enable(isi->pclk); + if (ret) + return ret; + + isi->icd = icd; + dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n", + icd->devnum); + return 0; +} +/* Called with .video_lock held */ +static void isi_camera_remove_device(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct atmel_isi *isi = ici->priv; + + BUG_ON(icd != isi->icd); + + clk_disable(isi->pclk); + isi->icd = NULL; + + dev_dbg(icd->parent, "Atmel ISI Camera driver detached from camera %d\n", + icd->devnum); +} + +static unsigned int isi_camera_poll(struct file *file, poll_table *pt) +{ + struct soc_camera_device *icd = file->private_data; + + return vb2_poll(&icd->vb2_vidq, file, pt); +} + +static int isi_camera_querycap(struct soc_camera_host *ici, + struct v4l2_capability *cap) +{ + strcpy(cap->driver, "atmel-isi"); + strcpy(cap->card, "Atmel Image Sensor Interface"); + cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING); + return 0; +} + +static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct atmel_isi *isi = ici->priv; + unsigned long bus_flags, camera_flags, common_flags; + int ret; + u32 cfg1 = 0; + + camera_flags = icd->ops->query_bus_param(icd); + + bus_flags = make_bus_param(isi); + common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); + dev_dbg(icd->parent, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n", + camera_flags, bus_flags, common_flags); + if (!common_flags) + return -EINVAL; + + /* Make choises, based on platform preferences */ + if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && + (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { + if (isi->pdata->hsync_act_low) + common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; + else + common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; + } + + if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && + (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { + if (isi->pdata->vsync_act_low) + common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; + else + common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; + } + + if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && + (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { + if (isi->pdata->pclk_act_falling) + common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; + else + common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; + } + + ret = icd->ops->set_bus_param(icd, common_flags); + if (ret < 0) { + dev_dbg(icd->parent, "Camera set_bus_param(%lx) returned %d\n", + common_flags, ret); + return ret; + } + + /* set bus param for ISI */ + if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) + cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW; + if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) + cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW; + if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) + cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING; + + if (isi->pdata->has_emb_sync) + cfg1 |= ISI_CFG1_EMB_SYNC; + if (isi->pdata->isi_full_mode) + cfg1 |= ISI_CFG1_FULL_MODE; + + isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); + isi_writel(isi, ISI_CFG1, cfg1); + + return 0; +} + +static struct soc_camera_host_ops isi_soc_camera_host_ops = { + .owner = THIS_MODULE, + .add = isi_camera_add_device, + .remove = isi_camera_remove_device, + .set_fmt = isi_camera_set_fmt, + .try_fmt = isi_camera_try_fmt, + .get_formats = isi_camera_get_formats, + .init_videobuf2 = isi_camera_init_videobuf, + .poll = isi_camera_poll, + .querycap = isi_camera_querycap, + .set_bus_param = isi_camera_set_bus_param, +}; + +/* -----------------------------------------------------------------------*/ +static int __devexit atmel_isi_remove(struct platform_device *pdev) +{ + struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); + struct atmel_isi *isi = container_of(soc_host, + struct atmel_isi, soc_host); + + free_irq(isi->irq, isi); + soc_camera_host_unregister(soc_host); + vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); + dma_free_coherent(&pdev->dev, + sizeof(struct fbd) * MAX_BUFFER_NUM, + isi->p_fb_descriptors, + isi->fb_descriptors_phys); + + iounmap(isi->regs); + clk_put(isi->pclk); + kfree(isi); + + return 0; +} + +static int __devinit atmel_isi_probe(struct platform_device *pdev) +{ + unsigned int irq; + struct atmel_isi *isi; + struct clk *pclk; + struct resource *regs; + int ret, i; + struct device *dev = &pdev->dev; + struct soc_camera_host *soc_host; + struct isi_platform_data *pdata; + + pdata = dev->platform_data; + if (!pdata || !pdata->data_width_flags) { + dev_err(&pdev->dev, + "No config available for Atmel ISI\n"); + return -EINVAL; + } + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) + return -ENXIO; + + pclk = clk_get(&pdev->dev, "isi_clk"); + if (IS_ERR(pclk)) + return PTR_ERR(pclk); + + isi = kzalloc(sizeof(struct atmel_isi), GFP_KERNEL); + if (!isi) { + ret = -ENOMEM; + dev_err(&pdev->dev, "Can't allocate interface!\n"); + goto err_alloc_isi; + } + + isi->pclk = pclk; + isi->pdata = pdata; + isi->active = NULL; + spin_lock_init(&isi->lock); + init_waitqueue_head(&isi->vsync_wq); + INIT_LIST_HEAD(&isi->video_buffer_list); + INIT_LIST_HEAD(&isi->dma_desc_head); + + isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, + sizeof(struct fbd) * MAX_BUFFER_NUM, + &isi->fb_descriptors_phys, + GFP_KERNEL); + if (!isi->p_fb_descriptors) { + ret = -ENOMEM; + dev_err(&pdev->dev, "Can't allocate descriptors!\n"); + goto err_alloc_descriptors; + } + + for (i = 0; i < MAX_BUFFER_NUM; i++) { + isi->dma_desc[i].p_fbd = isi->p_fb_descriptors + i; + isi->dma_desc[i].fbd_phys = isi->fb_descriptors_phys + + i * sizeof(struct fbd); + list_add(&isi->dma_desc[i].list, &isi->dma_desc_head); + } + + isi->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(isi->alloc_ctx)) { + ret = PTR_ERR(isi->alloc_ctx); + goto err_alloc_ctx; + } + + isi->regs = ioremap(regs->start, resource_size(regs)); + if (!isi->regs) { + ret = -ENOMEM; + goto err_ioremap; + } + + isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; + goto err_req_irq; + } + + ret = request_irq(irq, isi_interrupt, 0, "isi", isi); + if (ret) { + dev_err(&pdev->dev, "Unable to request irq %d\n", irq); + goto err_req_irq; + } + isi->irq = irq; + + soc_host = &isi->soc_host; + soc_host->drv_name = "isi-camera"; + soc_host->ops = &isi_soc_camera_host_ops; + soc_host->priv = isi; + soc_host->v4l2_dev.dev = &pdev->dev; + soc_host->nr = pdev->id; + + ret = soc_camera_host_register(soc_host); + if (ret) { + dev_err(&pdev->dev, "Unable to register soc camera host\n"); + goto err_register_soc_camera_host; + } + return 0; + +err_register_soc_camera_host: + free_irq(isi->irq, isi); +err_req_irq: + iounmap(isi->regs); +err_ioremap: + vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); +err_alloc_ctx: + dma_free_coherent(&pdev->dev, + sizeof(struct fbd) * MAX_BUFFER_NUM, + isi->p_fb_descriptors, + isi->fb_descriptors_phys); +err_alloc_descriptors: + kfree(isi); +err_alloc_isi: + clk_put(isi->pclk); + + return ret; +} + +static struct platform_driver atmel_isi_driver = { + .probe = atmel_isi_probe, + .remove = __devexit_p(atmel_isi_remove), + .driver = { + .name = "atmel_isi", + .owner = THIS_MODULE, + }, +}; + +static int __init atmel_isi_init_module(void) +{ + return platform_driver_probe(&atmel_isi_driver, &atmel_isi_probe); +} + +static void __exit atmel_isi_exit(void) +{ + platform_driver_unregister(&atmel_isi_driver); +} +module_init(atmel_isi_init_module); +module_exit(atmel_isi_exit); + +MODULE_AUTHOR("Josh Wu "); +MODULE_DESCRIPTION("The V4L2 driver for Atmel Linux"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("video"); diff --git a/drivers/media/video/au0828/au0828-core.c b/drivers/media/video/au0828/au0828-core.c index ca342e4c61fcdc5bf59108a5a2bb38ebbbea81b0..1e4ce5068ec2db52ca634f9a90e12ad66f755f6b 100644 --- a/drivers/media/video/au0828/au0828-core.c +++ b/drivers/media/video/au0828/au0828-core.c @@ -292,3 +292,4 @@ module_exit(au0828_exit); MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products"); MODULE_AUTHOR("Steven Toth "); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.0.2"); diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c index c03eb29a9ee6976fba68ae19b8a9dd6ebcb4b6b7..0b3e481ffe8c5b4bafb18f96fafc4632e5ff839d 100644 --- a/drivers/media/video/au0828/au0828-video.c +++ b/drivers/media/video/au0828/au0828-video.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -43,8 +42,6 @@ static DEFINE_MUTEX(au0828_sysfs_lock); -#define AU0828_VERSION_CODE KERNEL_VERSION(0, 0, 1) - /* ------------------------------------------------------------------ Videobuf operations ------------------------------------------------------------------*/ @@ -1254,8 +1251,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, dev->board.name, sizeof(cap->card)); strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info)); - cap->version = AU0828_VERSION_CODE; - /*set the device capabilities */ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 3c9e6c7e7b52313b82a229535fc23d7962fbfc62..5b15f63bf065cc8646753c5e1dc6f9c19d348da0 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -2892,13 +2892,10 @@ void __devinit bttv_idcard(struct bttv *btv) { unsigned int gpiobits; int i,type; - unsigned short tmp; /* read PCI subsystem ID */ - pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_ID, &tmp); - btv->cardid = tmp << 16; - pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_VENDOR_ID, &tmp); - btv->cardid |= tmp; + btv->cardid = btv->c.pci->subsystem_device << 16; + btv->cardid |= btv->c.pci->subsystem_vendor; if (0 != btv->cardid && 0xffffffff != btv->cardid) { /* look for the card */ diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 834a48394bce1bc4546f2754c24553a54119d862..14444de67d5e6d5ab8c618886529815eadf090cd 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -57,6 +57,7 @@ #include +#define BTTV_VERSION "0.9.19" unsigned int bttv_num; /* number of Bt848s in use */ struct bttv *bttvs[BTTV_MAX]; @@ -163,6 +164,7 @@ MODULE_PARM_DESC(radio_nr, "radio device numbers"); MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards"); MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); MODULE_LICENSE("GPL"); +MODULE_VERSION(BTTV_VERSION); /* ----------------------------------------------------------------------- */ /* sysfs */ @@ -2616,7 +2618,6 @@ static int bttv_querycap(struct file *file, void *priv, strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(btv->c.pci)); - cap->version = BTTV_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | @@ -3416,7 +3417,6 @@ static int radio_querycap(struct file *file, void *priv, strcpy(cap->driver, "bttv"); strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci)); - cap->version = BTTV_VERSION_CODE; cap->capabilities = V4L2_CAP_TUNER; return 0; @@ -4585,14 +4585,8 @@ static int __init bttv_init_module(void) bttv_num = 0; - printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n", - (BTTV_VERSION_CODE >> 16) & 0xff, - (BTTV_VERSION_CODE >> 8) & 0xff, - BTTV_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif + printk(KERN_INFO "bttv: driver version %s loaded\n", + BTTV_VERSION); if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) gbuffers = 2; if (gbufsize > BTTV_MAX_FBUF) diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index 9b776faf07416084896ecf94baef9f4906dd5875..318edf2830b4e7bfb0cde61582cadcd0b19ef3f6 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -25,9 +25,6 @@ #ifndef _BTTVP_H_ #define _BTTVP_H_ -#include -#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,18) - #include #include #include diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index c1193506131c3a37e3c347a8703771a98f3938af..f09df9dffaae50d3db2ac887757e53d4fb2ff61d 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -71,7 +71,6 @@ OTHER DEALINGS IN THE SOFTWARE. #include #include #include -#include #include #include #include @@ -647,7 +646,6 @@ static int qcam_querycap(struct file *file, void *priv, strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); strlcpy(vcap->card, "B&W Quickcam", sizeof(vcap->card)); strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); - vcap->version = KERNEL_VERSION(0, 0, 2); vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; return 0; } @@ -895,6 +893,7 @@ static struct qcam *qcam_init(struct parport *port) if (v4l2_device_register(NULL, v4l2_dev) < 0) { v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + kfree(qcam); return NULL; } @@ -1092,3 +1091,4 @@ module_init(init_bw_qcams); module_exit(exit_bw_qcams); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.0.3"); diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index 24fc00965a12d048be055498230b734b794283fa..cd8ff0473184ea06a14bf38f0b97bfc82db91917 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -517,7 +516,6 @@ static int qcam_querycap(struct file *file, void *priv, strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card)); strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); - vcap->version = KERNEL_VERSION(0, 0, 3); vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; return 0; } @@ -752,6 +750,7 @@ static struct qcam *qcam_init(struct parport *port) if (v4l2_device_register(NULL, v4l2_dev) < 0) { v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + kfree(qcam); return NULL; } @@ -886,6 +885,7 @@ static void __exit cqcam_cleanup(void) MODULE_AUTHOR("Philip Blundell "); MODULE_DESCRIPTION(BANNER); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.0.4"); module_init(cqcam_init); module_exit(cqcam_cleanup); diff --git a/drivers/media/video/cafe_ccic-regs.h b/drivers/media/video/cafe_ccic-regs.h deleted file mode 100644 index 8e2a87cdc791b1fa3018d9ee2fd0fef9f7283941..0000000000000000000000000000000000000000 --- a/drivers/media/video/cafe_ccic-regs.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Register definitions for the m88alp01 camera interface. Offsets in bytes - * as given in the spec. - * - * Copyright 2006 One Laptop Per Child Association, Inc. - * - * Written by Jonathan Corbet, corbet@lwn.net. - * - * This file may be distributed under the terms of the GNU General - * Public License, version 2. - */ -#define REG_Y0BAR 0x00 -#define REG_Y1BAR 0x04 -#define REG_Y2BAR 0x08 -/* ... */ - -#define REG_IMGPITCH 0x24 /* Image pitch register */ -#define IMGP_YP_SHFT 2 /* Y pitch params */ -#define IMGP_YP_MASK 0x00003ffc /* Y pitch field */ -#define IMGP_UVP_SHFT 18 /* UV pitch (planar) */ -#define IMGP_UVP_MASK 0x3ffc0000 -#define REG_IRQSTATRAW 0x28 /* RAW IRQ Status */ -#define IRQ_EOF0 0x00000001 /* End of frame 0 */ -#define IRQ_EOF1 0x00000002 /* End of frame 1 */ -#define IRQ_EOF2 0x00000004 /* End of frame 2 */ -#define IRQ_SOF0 0x00000008 /* Start of frame 0 */ -#define IRQ_SOF1 0x00000010 /* Start of frame 1 */ -#define IRQ_SOF2 0x00000020 /* Start of frame 2 */ -#define IRQ_OVERFLOW 0x00000040 /* FIFO overflow */ -#define IRQ_TWSIW 0x00010000 /* TWSI (smbus) write */ -#define IRQ_TWSIR 0x00020000 /* TWSI read */ -#define IRQ_TWSIE 0x00040000 /* TWSI error */ -#define TWSIIRQS (IRQ_TWSIW|IRQ_TWSIR|IRQ_TWSIE) -#define FRAMEIRQS (IRQ_EOF0|IRQ_EOF1|IRQ_EOF2|IRQ_SOF0|IRQ_SOF1|IRQ_SOF2) -#define ALLIRQS (TWSIIRQS|FRAMEIRQS|IRQ_OVERFLOW) -#define REG_IRQMASK 0x2c /* IRQ mask - same bits as IRQSTAT */ -#define REG_IRQSTAT 0x30 /* IRQ status / clear */ - -#define REG_IMGSIZE 0x34 /* Image size */ -#define IMGSZ_V_MASK 0x1fff0000 -#define IMGSZ_V_SHIFT 16 -#define IMGSZ_H_MASK 0x00003fff -#define REG_IMGOFFSET 0x38 /* IMage offset */ - -#define REG_CTRL0 0x3c /* Control 0 */ -#define C0_ENABLE 0x00000001 /* Makes the whole thing go */ - -/* Mask for all the format bits */ -#define C0_DF_MASK 0x00fffffc /* Bits 2-23 */ - -/* RGB ordering */ -#define C0_RGB4_RGBX 0x00000000 -#define C0_RGB4_XRGB 0x00000004 -#define C0_RGB4_BGRX 0x00000008 -#define C0_RGB4_XBGR 0x0000000c -#define C0_RGB5_RGGB 0x00000000 -#define C0_RGB5_GRBG 0x00000004 -#define C0_RGB5_GBRG 0x00000008 -#define C0_RGB5_BGGR 0x0000000c - -/* Spec has two fields for DIN and DOUT, but they must match, so - combine them here. */ -#define C0_DF_YUV 0x00000000 /* Data is YUV */ -#define C0_DF_RGB 0x000000a0 /* ... RGB */ -#define C0_DF_BAYER 0x00000140 /* ... Bayer */ -/* 8-8-8 must be missing from the below - ask */ -#define C0_RGBF_565 0x00000000 -#define C0_RGBF_444 0x00000800 -#define C0_RGB_BGR 0x00001000 /* Blue comes first */ -#define C0_YUV_PLANAR 0x00000000 /* YUV 422 planar format */ -#define C0_YUV_PACKED 0x00008000 /* YUV 422 packed */ -#define C0_YUV_420PL 0x0000a000 /* YUV 420 planar */ -/* Think that 420 packed must be 111 - ask */ -#define C0_YUVE_YUYV 0x00000000 /* Y1CbY0Cr */ -#define C0_YUVE_YVYU 0x00010000 /* Y1CrY0Cb */ -#define C0_YUVE_VYUY 0x00020000 /* CrY1CbY0 */ -#define C0_YUVE_UYVY 0x00030000 /* CbY1CrY0 */ -#define C0_YUVE_XYUV 0x00000000 /* 420: .YUV */ -#define C0_YUVE_XYVU 0x00010000 /* 420: .YVU */ -#define C0_YUVE_XUVY 0x00020000 /* 420: .UVY */ -#define C0_YUVE_XVUY 0x00030000 /* 420: .VUY */ -/* Bayer bits 18,19 if needed */ -#define C0_HPOL_LOW 0x01000000 /* HSYNC polarity active low */ -#define C0_VPOL_LOW 0x02000000 /* VSYNC polarity active low */ -#define C0_VCLK_LOW 0x04000000 /* VCLK on falling edge */ -#define C0_DOWNSCALE 0x08000000 /* Enable downscaler */ -#define C0_SIFM_MASK 0xc0000000 /* SIF mode bits */ -#define C0_SIF_HVSYNC 0x00000000 /* Use H/VSYNC */ -#define CO_SOF_NOSYNC 0x40000000 /* Use inband active signaling */ - - -#define REG_CTRL1 0x40 /* Control 1 */ -#define C1_444ALPHA 0x00f00000 /* Alpha field in RGB444 */ -#define C1_ALPHA_SHFT 20 -#define C1_DMAB32 0x00000000 /* 32-byte DMA burst */ -#define C1_DMAB16 0x02000000 /* 16-byte DMA burst */ -#define C1_DMAB64 0x04000000 /* 64-byte DMA burst */ -#define C1_DMAB_MASK 0x06000000 -#define C1_TWOBUFS 0x08000000 /* Use only two DMA buffers */ -#define C1_PWRDWN 0x10000000 /* Power down */ - -#define REG_CLKCTRL 0x88 /* Clock control */ -#define CLK_DIV_MASK 0x0000ffff /* Upper bits RW "reserved" */ - -#define REG_GPR 0xb4 /* General purpose register. This - controls inputs to the power and reset - pins on the OV7670 used with OLPC; - other deployments could differ. */ -#define GPR_C1EN 0x00000020 /* Pad 1 (power down) enable */ -#define GPR_C0EN 0x00000010 /* Pad 0 (reset) enable */ -#define GPR_C1 0x00000002 /* Control 1 value */ -/* - * Control 0 is wired to reset on OLPC machines. For ov7x sensors, - * it is active low, for 0v6x, instead, it's active high. What - * fun. - */ -#define GPR_C0 0x00000001 /* Control 0 value */ - -#define REG_TWSIC0 0xb8 /* TWSI (smbus) control 0 */ -#define TWSIC0_EN 0x00000001 /* TWSI enable */ -#define TWSIC0_MODE 0x00000002 /* 1 = 16-bit, 0 = 8-bit */ -#define TWSIC0_SID 0x000003fc /* Slave ID */ -#define TWSIC0_SID_SHIFT 2 -#define TWSIC0_CLKDIV 0x0007fc00 /* Clock divider */ -#define TWSIC0_MASKACK 0x00400000 /* Mask ack from sensor */ -#define TWSIC0_OVMAGIC 0x00800000 /* Make it work on OV sensors */ - -#define REG_TWSIC1 0xbc /* TWSI control 1 */ -#define TWSIC1_DATA 0x0000ffff /* Data to/from camchip */ -#define TWSIC1_ADDR 0x00ff0000 /* Address (register) */ -#define TWSIC1_ADDR_SHIFT 16 -#define TWSIC1_READ 0x01000000 /* Set for read op */ -#define TWSIC1_WSTAT 0x02000000 /* Write status */ -#define TWSIC1_RVALID 0x04000000 /* Read data valid */ -#define TWSIC1_ERROR 0x08000000 /* Something screwed up */ - - -#define REG_UBAR 0xc4 /* Upper base address register */ - -/* - * Here's the weird global control registers which are said to live - * way up here. - */ -#define REG_GL_CSR 0x3004 /* Control/status register */ -#define GCSR_SRS 0x00000001 /* SW Reset set */ -#define GCSR_SRC 0x00000002 /* SW Reset clear */ -#define GCSR_MRS 0x00000004 /* Master reset set */ -#define GCSR_MRC 0x00000008 /* HW Reset clear */ -#define GCSR_CCIC_EN 0x00004000 /* CCIC Clock enable */ -#define REG_GL_IMASK 0x300c /* Interrupt mask register */ -#define GIMSK_CCIC_EN 0x00000004 /* CCIC Interrupt enable */ - -#define REG_GL_FCR 0x3038 /* GPIO functional control register */ -#define GFCR_GPIO_ON 0x08 /* Camera GPIO enabled */ -#define REG_GL_GPIOR 0x315c /* GPIO register */ -#define GGPIO_OUT 0x80000 /* GPIO output */ -#define GGPIO_VAL 0x00008 /* Output pin value */ - -#define REG_LEN REG_GL_IMASK + 4 - - -/* - * Useful stuff that probably belongs somewhere global. - */ -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c deleted file mode 100644 index 66470339849329b9a197c9b81b6c21f73de93d50..0000000000000000000000000000000000000000 --- a/drivers/media/video/cafe_ccic.c +++ /dev/null @@ -1,2267 +0,0 @@ -/* - * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe" - * multifunction chip. Currently works with the Omnivision OV7670 - * sensor. - * - * The data sheet for this device can be found at: - * http://www.marvell.com/products/pc_connectivity/88alp01/ - * - * Copyright 2006 One Laptop Per Child Association, Inc. - * Copyright 2006-7 Jonathan Corbet - * - * Written by Jonathan Corbet, corbet@lwn.net. - * - * v4l2_device/v4l2_subdev conversion by: - * Copyright (C) 2009 Hans Verkuil - * - * Note: this conversion is untested! Please contact the linux-media - * mailinglist if you can test this, together with the test results. - * - * This file may be distributed under the terms of the GNU General - * Public License, version 2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "ov7670.h" -#include "cafe_ccic-regs.h" - -#define CAFE_VERSION 0x000002 - - -/* - * Parameters. - */ -MODULE_AUTHOR("Jonathan Corbet "); -MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("Video"); - -/* - * Internal DMA buffer management. Since the controller cannot do S/G I/O, - * we must have physically contiguous buffers to bring frames into. - * These parameters control how many buffers we use, whether we - * allocate them at load time (better chance of success, but nails down - * memory) or when somebody tries to use the camera (riskier), and, - * for load-time allocation, how big they should be. - * - * The controller can cycle through three buffers. We could use - * more by flipping pointers around, but it probably makes little - * sense. - */ - -#define MAX_DMA_BUFS 3 -static int alloc_bufs_at_read; -module_param(alloc_bufs_at_read, bool, 0444); -MODULE_PARM_DESC(alloc_bufs_at_read, - "Non-zero value causes DMA buffers to be allocated when the " - "video capture device is read, rather than at module load " - "time. This saves memory, but decreases the chances of " - "successfully getting those buffers."); - -static int n_dma_bufs = 3; -module_param(n_dma_bufs, uint, 0644); -MODULE_PARM_DESC(n_dma_bufs, - "The number of DMA buffers to allocate. Can be either two " - "(saves memory, makes timing tighter) or three."); - -static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2; /* Worst case */ -module_param(dma_buf_size, uint, 0444); -MODULE_PARM_DESC(dma_buf_size, - "The size of the allocated DMA buffers. If actual operating " - "parameters require larger buffers, an attempt to reallocate " - "will be made."); - -static int min_buffers = 1; -module_param(min_buffers, uint, 0644); -MODULE_PARM_DESC(min_buffers, - "The minimum number of streaming I/O buffers we are willing " - "to work with."); - -static int max_buffers = 10; -module_param(max_buffers, uint, 0644); -MODULE_PARM_DESC(max_buffers, - "The maximum number of streaming I/O buffers an application " - "will be allowed to allocate. These buffers are big and live " - "in vmalloc space."); - -static int flip; -module_param(flip, bool, 0444); -MODULE_PARM_DESC(flip, - "If set, the sensor will be instructed to flip the image " - "vertically."); - - -enum cafe_state { - S_NOTREADY, /* Not yet initialized */ - S_IDLE, /* Just hanging around */ - S_FLAKED, /* Some sort of problem */ - S_SINGLEREAD, /* In read() */ - S_SPECREAD, /* Speculative read (for future read()) */ - S_STREAMING /* Streaming data */ -}; - -/* - * Tracking of streaming I/O buffers. - */ -struct cafe_sio_buffer { - struct list_head list; - struct v4l2_buffer v4lbuf; - char *buffer; /* Where it lives in kernel space */ - int mapcount; - struct cafe_camera *cam; -}; - -/* - * A description of one of our devices. - * Locking: controlled by s_mutex. Certain fields, however, require - * the dev_lock spinlock; they are marked as such by comments. - * dev_lock is also required for access to device registers. - */ -struct cafe_camera -{ - struct v4l2_device v4l2_dev; - enum cafe_state state; - unsigned long flags; /* Buffer status, mainly (dev_lock) */ - int users; /* How many open FDs */ - struct file *owner; /* Who has data access (v4l2) */ - - /* - * Subsystem structures. - */ - struct pci_dev *pdev; - struct video_device vdev; - struct i2c_adapter i2c_adapter; - struct v4l2_subdev *sensor; - unsigned short sensor_addr; - - unsigned char __iomem *regs; - struct list_head dev_list; /* link to other devices */ - - /* DMA buffers */ - unsigned int nbufs; /* How many are alloc'd */ - int next_buf; /* Next to consume (dev_lock) */ - unsigned int dma_buf_size; /* allocated size */ - void *dma_bufs[MAX_DMA_BUFS]; /* Internal buffer addresses */ - dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */ - unsigned int specframes; /* Unconsumed spec frames (dev_lock) */ - unsigned int sequence; /* Frame sequence number */ - unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual buffers */ - - /* Streaming buffers */ - unsigned int n_sbufs; /* How many we have */ - struct cafe_sio_buffer *sb_bufs; /* The array of housekeeping structs */ - struct list_head sb_avail; /* Available for data (we own) (dev_lock) */ - struct list_head sb_full; /* With data (user space owns) (dev_lock) */ - struct tasklet_struct s_tasklet; - - /* Current operating parameters */ - u32 sensor_type; /* Currently ov7670 only */ - struct v4l2_pix_format pix_format; - enum v4l2_mbus_pixelcode mbus_code; - - /* Locks */ - struct mutex s_mutex; /* Access to this structure */ - spinlock_t dev_lock; /* Access to device */ - - /* Misc */ - wait_queue_head_t smbus_wait; /* Waiting on i2c events */ - wait_queue_head_t iowait; /* Waiting on frame data */ -}; - -/* - * Status flags. Always manipulated with bit operations. - */ -#define CF_BUF0_VALID 0 /* Buffers valid - first three */ -#define CF_BUF1_VALID 1 -#define CF_BUF2_VALID 2 -#define CF_DMA_ACTIVE 3 /* A frame is incoming */ -#define CF_CONFIG_NEEDED 4 /* Must configure hardware */ - -#define sensor_call(cam, o, f, args...) \ - v4l2_subdev_call(cam->sensor, o, f, ##args) - -static inline struct cafe_camera *to_cam(struct v4l2_device *dev) -{ - return container_of(dev, struct cafe_camera, v4l2_dev); -} - -static struct cafe_format_struct { - __u8 *desc; - __u32 pixelformat; - int bpp; /* Bytes per pixel */ - enum v4l2_mbus_pixelcode mbus_code; -} cafe_formats[] = { - { - .desc = "YUYV 4:2:2", - .pixelformat = V4L2_PIX_FMT_YUYV, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, - .bpp = 2, - }, - { - .desc = "RGB 444", - .pixelformat = V4L2_PIX_FMT_RGB444, - .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE, - .bpp = 2, - }, - { - .desc = "RGB 565", - .pixelformat = V4L2_PIX_FMT_RGB565, - .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, - .bpp = 2, - }, - { - .desc = "Raw RGB Bayer", - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .mbus_code = V4L2_MBUS_FMT_SBGGR8_1X8, - .bpp = 1 - }, -}; -#define N_CAFE_FMTS ARRAY_SIZE(cafe_formats) - -static struct cafe_format_struct *cafe_find_format(u32 pixelformat) -{ - unsigned i; - - for (i = 0; i < N_CAFE_FMTS; i++) - if (cafe_formats[i].pixelformat == pixelformat) - return cafe_formats + i; - /* Not found? Then return the first format. */ - return cafe_formats; -} - -/* - * Start over with DMA buffers - dev_lock needed. - */ -static void cafe_reset_buffers(struct cafe_camera *cam) -{ - int i; - - cam->next_buf = -1; - for (i = 0; i < cam->nbufs; i++) - clear_bit(i, &cam->flags); - cam->specframes = 0; -} - -static inline int cafe_needs_config(struct cafe_camera *cam) -{ - return test_bit(CF_CONFIG_NEEDED, &cam->flags); -} - -static void cafe_set_config_needed(struct cafe_camera *cam, int needed) -{ - if (needed) - set_bit(CF_CONFIG_NEEDED, &cam->flags); - else - clear_bit(CF_CONFIG_NEEDED, &cam->flags); -} - - - - -/* - * Debugging and related. - */ -#define cam_err(cam, fmt, arg...) \ - dev_err(&(cam)->pdev->dev, fmt, ##arg); -#define cam_warn(cam, fmt, arg...) \ - dev_warn(&(cam)->pdev->dev, fmt, ##arg); -#define cam_dbg(cam, fmt, arg...) \ - dev_dbg(&(cam)->pdev->dev, fmt, ##arg); - - -/* ---------------------------------------------------------------------*/ - -/* - * Device register I/O - */ -static inline void cafe_reg_write(struct cafe_camera *cam, unsigned int reg, - unsigned int val) -{ - iowrite32(val, cam->regs + reg); -} - -static inline unsigned int cafe_reg_read(struct cafe_camera *cam, - unsigned int reg) -{ - return ioread32(cam->regs + reg); -} - - -static inline void cafe_reg_write_mask(struct cafe_camera *cam, unsigned int reg, - unsigned int val, unsigned int mask) -{ - unsigned int v = cafe_reg_read(cam, reg); - - v = (v & ~mask) | (val & mask); - cafe_reg_write(cam, reg, v); -} - -static inline void cafe_reg_clear_bit(struct cafe_camera *cam, - unsigned int reg, unsigned int val) -{ - cafe_reg_write_mask(cam, reg, 0, val); -} - -static inline void cafe_reg_set_bit(struct cafe_camera *cam, - unsigned int reg, unsigned int val) -{ - cafe_reg_write_mask(cam, reg, val, val); -} - - - -/* -------------------------------------------------------------------- */ -/* - * The I2C/SMBUS interface to the camera itself starts here. The - * controller handles SMBUS itself, presenting a relatively simple register - * interface; all we have to do is to tell it where to route the data. - */ -#define CAFE_SMBUS_TIMEOUT (HZ) /* generous */ - -static int cafe_smbus_write_done(struct cafe_camera *cam) -{ - unsigned long flags; - int c1; - - /* - * We must delay after the interrupt, or the controller gets confused - * and never does give us good status. Fortunately, we don't do this - * often. - */ - udelay(20); - spin_lock_irqsave(&cam->dev_lock, flags); - c1 = cafe_reg_read(cam, REG_TWSIC1); - spin_unlock_irqrestore(&cam->dev_lock, flags); - return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT; -} - -static int cafe_smbus_write_data(struct cafe_camera *cam, - u16 addr, u8 command, u8 value) -{ - unsigned int rval; - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); - rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */ - /* - * Marvell sez set clkdiv to all 1's for now. - */ - rval |= TWSIC0_CLKDIV; - cafe_reg_write(cam, REG_TWSIC0, rval); - (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */ - rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); - cafe_reg_write(cam, REG_TWSIC1, rval); - spin_unlock_irqrestore(&cam->dev_lock, flags); - - /* Unfortunately, reading TWSIC1 too soon after sending a command - * causes the device to die. - * Use a busy-wait because we often send a large quantity of small - * commands at-once; using msleep() would cause a lot of context - * switches which take longer than 2ms, resulting in a noticeable - * boot-time and capture-start delays. - */ - mdelay(2); - - /* - * Another sad fact is that sometimes, commands silently complete but - * cafe_smbus_write_done() never becomes aware of this. - * This happens at random and appears to possible occur with any - * command. - * We don't understand why this is. We work around this issue - * with the timeout in the wait below, assuming that all commands - * complete within the timeout. - */ - wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam), - CAFE_SMBUS_TIMEOUT); - - spin_lock_irqsave(&cam->dev_lock, flags); - rval = cafe_reg_read(cam, REG_TWSIC1); - spin_unlock_irqrestore(&cam->dev_lock, flags); - - if (rval & TWSIC1_WSTAT) { - cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr, - command, value); - return -EIO; - } - if (rval & TWSIC1_ERROR) { - cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr, - command, value); - return -EIO; - } - return 0; -} - - - -static int cafe_smbus_read_done(struct cafe_camera *cam) -{ - unsigned long flags; - int c1; - - /* - * We must delay after the interrupt, or the controller gets confused - * and never does give us good status. Fortunately, we don't do this - * often. - */ - udelay(20); - spin_lock_irqsave(&cam->dev_lock, flags); - c1 = cafe_reg_read(cam, REG_TWSIC1); - spin_unlock_irqrestore(&cam->dev_lock, flags); - return c1 & (TWSIC1_RVALID|TWSIC1_ERROR); -} - - - -static int cafe_smbus_read_data(struct cafe_camera *cam, - u16 addr, u8 command, u8 *value) -{ - unsigned int rval; - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); - rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */ - /* - * Marvel sez set clkdiv to all 1's for now. - */ - rval |= TWSIC0_CLKDIV; - cafe_reg_write(cam, REG_TWSIC0, rval); - (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */ - rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); - cafe_reg_write(cam, REG_TWSIC1, rval); - spin_unlock_irqrestore(&cam->dev_lock, flags); - - wait_event_timeout(cam->smbus_wait, - cafe_smbus_read_done(cam), CAFE_SMBUS_TIMEOUT); - spin_lock_irqsave(&cam->dev_lock, flags); - rval = cafe_reg_read(cam, REG_TWSIC1); - spin_unlock_irqrestore(&cam->dev_lock, flags); - - if (rval & TWSIC1_ERROR) { - cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command); - return -EIO; - } - if (! (rval & TWSIC1_RVALID)) { - cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr, - command); - return -EIO; - } - *value = rval & 0xff; - return 0; -} - -/* - * Perform a transfer over SMBUS. This thing is called under - * the i2c bus lock, so we shouldn't race with ourselves... - */ -static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr, - unsigned short flags, char rw, u8 command, - int size, union i2c_smbus_data *data) -{ - struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter); - struct cafe_camera *cam = to_cam(v4l2_dev); - int ret = -EINVAL; - - /* - * This interface would appear to only do byte data ops. OK - * it can do word too, but the cam chip has no use for that. - */ - if (size != I2C_SMBUS_BYTE_DATA) { - cam_err(cam, "funky xfer size %d\n", size); - return -EINVAL; - } - - if (rw == I2C_SMBUS_WRITE) - ret = cafe_smbus_write_data(cam, addr, command, data->byte); - else if (rw == I2C_SMBUS_READ) - ret = cafe_smbus_read_data(cam, addr, command, &data->byte); - return ret; -} - - -static void cafe_smbus_enable_irq(struct cafe_camera *cam) -{ - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - cafe_reg_set_bit(cam, REG_IRQMASK, TWSIIRQS); - spin_unlock_irqrestore(&cam->dev_lock, flags); -} - -static u32 cafe_smbus_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_SMBUS_READ_BYTE_DATA | - I2C_FUNC_SMBUS_WRITE_BYTE_DATA; -} - -static struct i2c_algorithm cafe_smbus_algo = { - .smbus_xfer = cafe_smbus_xfer, - .functionality = cafe_smbus_func -}; - -/* Somebody is on the bus */ -static void cafe_ctlr_stop_dma(struct cafe_camera *cam); -static void cafe_ctlr_power_down(struct cafe_camera *cam); - -static int cafe_smbus_setup(struct cafe_camera *cam) -{ - struct i2c_adapter *adap = &cam->i2c_adapter; - int ret; - - cafe_smbus_enable_irq(cam); - adap->owner = THIS_MODULE; - adap->algo = &cafe_smbus_algo; - strcpy(adap->name, "cafe_ccic"); - adap->dev.parent = &cam->pdev->dev; - i2c_set_adapdata(adap, &cam->v4l2_dev); - ret = i2c_add_adapter(adap); - if (ret) - printk(KERN_ERR "Unable to register cafe i2c adapter\n"); - return ret; -} - -static void cafe_smbus_shutdown(struct cafe_camera *cam) -{ - i2c_del_adapter(&cam->i2c_adapter); -} - - -/* ------------------------------------------------------------------- */ -/* - * Deal with the controller. - */ - -/* - * Do everything we think we need to have the interface operating - * according to the desired format. - */ -static void cafe_ctlr_dma(struct cafe_camera *cam) -{ - /* - * Store the first two Y buffers (we aren't supporting - * planar formats for now, so no UV bufs). Then either - * set the third if it exists, or tell the controller - * to just use two. - */ - cafe_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]); - cafe_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]); - if (cam->nbufs > 2) { - cafe_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]); - cafe_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS); - } - else - cafe_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS); - cafe_reg_write(cam, REG_UBAR, 0); /* 32 bits only for now */ -} - -static void cafe_ctlr_image(struct cafe_camera *cam) -{ - int imgsz; - struct v4l2_pix_format *fmt = &cam->pix_format; - - imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) | - (fmt->bytesperline & IMGSZ_H_MASK); - cafe_reg_write(cam, REG_IMGSIZE, imgsz); - cafe_reg_write(cam, REG_IMGOFFSET, 0); - /* YPITCH just drops the last two bits */ - cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline, - IMGP_YP_MASK); - /* - * Tell the controller about the image format we are using. - */ - switch (cam->pix_format.pixelformat) { - case V4L2_PIX_FMT_YUYV: - cafe_reg_write_mask(cam, REG_CTRL0, - C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV, - C0_DF_MASK); - break; - - case V4L2_PIX_FMT_RGB444: - cafe_reg_write_mask(cam, REG_CTRL0, - C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB, - C0_DF_MASK); - /* Alpha value? */ - break; - - case V4L2_PIX_FMT_RGB565: - cafe_reg_write_mask(cam, REG_CTRL0, - C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR, - C0_DF_MASK); - break; - - default: - cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat); - break; - } - /* - * Make sure it knows we want to use hsync/vsync. - */ - cafe_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC, - C0_SIFM_MASK); -} - - -/* - * Configure the controller for operation; caller holds the - * device mutex. - */ -static int cafe_ctlr_configure(struct cafe_camera *cam) -{ - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - cafe_ctlr_dma(cam); - cafe_ctlr_image(cam); - cafe_set_config_needed(cam, 0); - spin_unlock_irqrestore(&cam->dev_lock, flags); - return 0; -} - -static void cafe_ctlr_irq_enable(struct cafe_camera *cam) -{ - /* - * Clear any pending interrupts, since we do not - * expect to have I/O active prior to enabling. - */ - cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); - cafe_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS); -} - -static void cafe_ctlr_irq_disable(struct cafe_camera *cam) -{ - cafe_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS); -} - -/* - * Make the controller start grabbing images. Everything must - * be set up before doing this. - */ -static void cafe_ctlr_start(struct cafe_camera *cam) -{ - /* set_bit performs a read, so no other barrier should be - needed here */ - cafe_reg_set_bit(cam, REG_CTRL0, C0_ENABLE); -} - -static void cafe_ctlr_stop(struct cafe_camera *cam) -{ - cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); -} - -static void cafe_ctlr_init(struct cafe_camera *cam) -{ - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - /* - * Added magic to bring up the hardware on the B-Test board - */ - cafe_reg_write(cam, 0x3038, 0x8); - cafe_reg_write(cam, 0x315c, 0x80008); - /* - * Go through the dance needed to wake the device up. - * Note that these registers are global and shared - * with the NAND and SD devices. Interaction between the - * three still needs to be examined. - */ - cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */ - cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC); - cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS); - /* - * Here we must wait a bit for the controller to come around. - */ - spin_unlock_irqrestore(&cam->dev_lock, flags); - msleep(5); - spin_lock_irqsave(&cam->dev_lock, flags); - - cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC); - cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN); - /* - * Make sure it's not powered down. - */ - cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); - /* - * Turn off the enable bit. It sure should be off anyway, - * but it's good to be sure. - */ - cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); - /* - * Mask all interrupts. - */ - cafe_reg_write(cam, REG_IRQMASK, 0); - /* - * Clock the sensor appropriately. Controller clock should - * be 48MHz, sensor "typical" value is half that. - */ - cafe_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK); - spin_unlock_irqrestore(&cam->dev_lock, flags); -} - - -/* - * Stop the controller, and don't return until we're really sure that no - * further DMA is going on. - */ -static void cafe_ctlr_stop_dma(struct cafe_camera *cam) -{ - unsigned long flags; - - /* - * Theory: stop the camera controller (whether it is operating - * or not). Delay briefly just in case we race with the SOF - * interrupt, then wait until no DMA is active. - */ - spin_lock_irqsave(&cam->dev_lock, flags); - cafe_ctlr_stop(cam); - spin_unlock_irqrestore(&cam->dev_lock, flags); - mdelay(1); - wait_event_timeout(cam->iowait, - !test_bit(CF_DMA_ACTIVE, &cam->flags), HZ); - if (test_bit(CF_DMA_ACTIVE, &cam->flags)) - cam_err(cam, "Timeout waiting for DMA to end\n"); - /* This would be bad news - what now? */ - spin_lock_irqsave(&cam->dev_lock, flags); - cam->state = S_IDLE; - cafe_ctlr_irq_disable(cam); - spin_unlock_irqrestore(&cam->dev_lock, flags); -} - -/* - * Power up and down. - */ -static void cafe_ctlr_power_up(struct cafe_camera *cam) -{ - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); - /* - * Part one of the sensor dance: turn the global - * GPIO signal on. - */ - cafe_reg_write(cam, REG_GL_FCR, GFCR_GPIO_ON); - cafe_reg_write(cam, REG_GL_GPIOR, GGPIO_OUT|GGPIO_VAL); - /* - * Put the sensor into operational mode (assumes OLPC-style - * wiring). Control 0 is reset - set to 1 to operate. - * Control 1 is power down, set to 0 to operate. - */ - cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */ -/* mdelay(1); */ /* Marvell says 1ms will do it */ - cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); -/* mdelay(1); */ /* Enough? */ - spin_unlock_irqrestore(&cam->dev_lock, flags); - msleep(5); /* Just to be sure */ -} - -static void cafe_ctlr_power_down(struct cafe_camera *cam) -{ - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1); - cafe_reg_write(cam, REG_GL_FCR, GFCR_GPIO_ON); - cafe_reg_write(cam, REG_GL_GPIOR, GGPIO_OUT); - cafe_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN); - spin_unlock_irqrestore(&cam->dev_lock, flags); -} - -/* -------------------------------------------------------------------- */ -/* - * Communications with the sensor. - */ - -static int __cafe_cam_reset(struct cafe_camera *cam) -{ - return sensor_call(cam, core, reset, 0); -} - -/* - * We have found the sensor on the i2c. Let's try to have a - * conversation. - */ -static int cafe_cam_init(struct cafe_camera *cam) -{ - struct v4l2_dbg_chip_ident chip; - int ret; - - mutex_lock(&cam->s_mutex); - if (cam->state != S_NOTREADY) - cam_warn(cam, "Cam init with device in funky state %d", - cam->state); - ret = __cafe_cam_reset(cam); - if (ret) - goto out; - chip.ident = V4L2_IDENT_NONE; - chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR; - chip.match.addr = cam->sensor_addr; - ret = sensor_call(cam, core, g_chip_ident, &chip); - if (ret) - goto out; - cam->sensor_type = chip.ident; - if (cam->sensor_type != V4L2_IDENT_OV7670) { - cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type); - ret = -EINVAL; - goto out; - } -/* Get/set parameters? */ - ret = 0; - cam->state = S_IDLE; - out: - cafe_ctlr_power_down(cam); - mutex_unlock(&cam->s_mutex); - return ret; -} - -/* - * Configure the sensor to match the parameters we have. Caller should - * hold s_mutex - */ -static int cafe_cam_set_flip(struct cafe_camera *cam) -{ - struct v4l2_control ctrl; - - memset(&ctrl, 0, sizeof(ctrl)); - ctrl.id = V4L2_CID_VFLIP; - ctrl.value = flip; - return sensor_call(cam, core, s_ctrl, &ctrl); -} - - -static int cafe_cam_configure(struct cafe_camera *cam) -{ - struct v4l2_mbus_framefmt mbus_fmt; - int ret; - - v4l2_fill_mbus_format(&mbus_fmt, &cam->pix_format, cam->mbus_code); - ret = sensor_call(cam, core, init, 0); - if (ret == 0) - ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt); - /* - * OV7670 does weird things if flip is set *before* format... - */ - ret += cafe_cam_set_flip(cam); - return ret; -} - -/* -------------------------------------------------------------------- */ -/* - * DMA buffer management. These functions need s_mutex held. - */ - -/* FIXME: this is inefficient as hell, since dma_alloc_coherent just - * does a get_free_pages() call, and we waste a good chunk of an orderN - * allocation. Should try to allocate the whole set in one chunk. - */ -static int cafe_alloc_dma_bufs(struct cafe_camera *cam, int loadtime) -{ - int i; - - cafe_set_config_needed(cam, 1); - if (loadtime) - cam->dma_buf_size = dma_buf_size; - else - cam->dma_buf_size = cam->pix_format.sizeimage; - if (n_dma_bufs > 3) - n_dma_bufs = 3; - - cam->nbufs = 0; - for (i = 0; i < n_dma_bufs; i++) { - cam->dma_bufs[i] = dma_alloc_coherent(&cam->pdev->dev, - cam->dma_buf_size, cam->dma_handles + i, - GFP_KERNEL); - if (cam->dma_bufs[i] == NULL) { - cam_warn(cam, "Failed to allocate DMA buffer\n"); - break; - } - /* For debug, remove eventually */ - memset(cam->dma_bufs[i], 0xcc, cam->dma_buf_size); - (cam->nbufs)++; - } - - switch (cam->nbufs) { - case 1: - dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size, - cam->dma_bufs[0], cam->dma_handles[0]); - cam->nbufs = 0; - case 0: - cam_err(cam, "Insufficient DMA buffers, cannot operate\n"); - return -ENOMEM; - - case 2: - if (n_dma_bufs > 2) - cam_warn(cam, "Will limp along with only 2 buffers\n"); - break; - } - return 0; -} - -static void cafe_free_dma_bufs(struct cafe_camera *cam) -{ - int i; - - for (i = 0; i < cam->nbufs; i++) { - dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size, - cam->dma_bufs[i], cam->dma_handles[i]); - cam->dma_bufs[i] = NULL; - } - cam->nbufs = 0; -} - - - - - -/* ----------------------------------------------------------------------- */ -/* - * Here starts the V4L2 interface code. - */ - -/* - * Read an image from the device. - */ -static ssize_t cafe_deliver_buffer(struct cafe_camera *cam, - char __user *buffer, size_t len, loff_t *pos) -{ - int bufno; - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - if (cam->next_buf < 0) { - cam_err(cam, "deliver_buffer: No next buffer\n"); - spin_unlock_irqrestore(&cam->dev_lock, flags); - return -EIO; - } - bufno = cam->next_buf; - clear_bit(bufno, &cam->flags); - if (++(cam->next_buf) >= cam->nbufs) - cam->next_buf = 0; - if (! test_bit(cam->next_buf, &cam->flags)) - cam->next_buf = -1; - cam->specframes = 0; - spin_unlock_irqrestore(&cam->dev_lock, flags); - - if (len > cam->pix_format.sizeimage) - len = cam->pix_format.sizeimage; - if (copy_to_user(buffer, cam->dma_bufs[bufno], len)) - return -EFAULT; - (*pos) += len; - return len; -} - -/* - * Get everything ready, and start grabbing frames. - */ -static int cafe_read_setup(struct cafe_camera *cam, enum cafe_state state) -{ - int ret; - unsigned long flags; - - /* - * Configuration. If we still don't have DMA buffers, - * make one last, desperate attempt. - */ - if (cam->nbufs == 0) - if (cafe_alloc_dma_bufs(cam, 0)) - return -ENOMEM; - - if (cafe_needs_config(cam)) { - cafe_cam_configure(cam); - ret = cafe_ctlr_configure(cam); - if (ret) - return ret; - } - - /* - * Turn it loose. - */ - spin_lock_irqsave(&cam->dev_lock, flags); - cafe_reset_buffers(cam); - cafe_ctlr_irq_enable(cam); - cam->state = state; - cafe_ctlr_start(cam); - spin_unlock_irqrestore(&cam->dev_lock, flags); - return 0; -} - - -static ssize_t cafe_v4l_read(struct file *filp, - char __user *buffer, size_t len, loff_t *pos) -{ - struct cafe_camera *cam = filp->private_data; - int ret = 0; - - /* - * Perhaps we're in speculative read mode and already - * have data? - */ - mutex_lock(&cam->s_mutex); - if (cam->state == S_SPECREAD) { - if (cam->next_buf >= 0) { - ret = cafe_deliver_buffer(cam, buffer, len, pos); - if (ret != 0) - goto out_unlock; - } - } else if (cam->state == S_FLAKED || cam->state == S_NOTREADY) { - ret = -EIO; - goto out_unlock; - } else if (cam->state != S_IDLE) { - ret = -EBUSY; - goto out_unlock; - } - - /* - * v4l2: multiple processes can open the device, but only - * one gets to grab data from it. - */ - if (cam->owner && cam->owner != filp) { - ret = -EBUSY; - goto out_unlock; - } - cam->owner = filp; - - /* - * Do setup if need be. - */ - if (cam->state != S_SPECREAD) { - ret = cafe_read_setup(cam, S_SINGLEREAD); - if (ret) - goto out_unlock; - } - /* - * Wait for something to happen. This should probably - * be interruptible (FIXME). - */ - wait_event_timeout(cam->iowait, cam->next_buf >= 0, HZ); - if (cam->next_buf < 0) { - cam_err(cam, "read() operation timed out\n"); - cafe_ctlr_stop_dma(cam); - ret = -EIO; - goto out_unlock; - } - /* - * Give them their data and we should be done. - */ - ret = cafe_deliver_buffer(cam, buffer, len, pos); - - out_unlock: - mutex_unlock(&cam->s_mutex); - return ret; -} - - - - - - - - -/* - * Streaming I/O support. - */ - - - -static int cafe_vidioc_streamon(struct file *filp, void *priv, - enum v4l2_buf_type type) -{ - struct cafe_camera *cam = filp->private_data; - int ret = -EINVAL; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - goto out; - mutex_lock(&cam->s_mutex); - if (cam->state != S_IDLE || cam->n_sbufs == 0) - goto out_unlock; - - cam->sequence = 0; - ret = cafe_read_setup(cam, S_STREAMING); - - out_unlock: - mutex_unlock(&cam->s_mutex); - out: - return ret; -} - - -static int cafe_vidioc_streamoff(struct file *filp, void *priv, - enum v4l2_buf_type type) -{ - struct cafe_camera *cam = filp->private_data; - int ret = -EINVAL; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - goto out; - mutex_lock(&cam->s_mutex); - if (cam->state != S_STREAMING) - goto out_unlock; - - cafe_ctlr_stop_dma(cam); - ret = 0; - - out_unlock: - mutex_unlock(&cam->s_mutex); - out: - return ret; -} - - - -static int cafe_setup_siobuf(struct cafe_camera *cam, int index) -{ - struct cafe_sio_buffer *buf = cam->sb_bufs + index; - - INIT_LIST_HEAD(&buf->list); - buf->v4lbuf.length = PAGE_ALIGN(cam->pix_format.sizeimage); - buf->buffer = vmalloc_user(buf->v4lbuf.length); - if (buf->buffer == NULL) - return -ENOMEM; - buf->mapcount = 0; - buf->cam = cam; - - buf->v4lbuf.index = index; - buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf->v4lbuf.field = V4L2_FIELD_NONE; - buf->v4lbuf.memory = V4L2_MEMORY_MMAP; - /* - * Offset: must be 32-bit even on a 64-bit system. videobuf-dma-sg - * just uses the length times the index, but the spec warns - * against doing just that - vma merging problems. So we - * leave a gap between each pair of buffers. - */ - buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length; - return 0; -} - -static int cafe_free_sio_buffers(struct cafe_camera *cam) -{ - int i; - - /* - * If any buffers are mapped, we cannot free them at all. - */ - for (i = 0; i < cam->n_sbufs; i++) - if (cam->sb_bufs[i].mapcount > 0) - return -EBUSY; - /* - * OK, let's do it. - */ - for (i = 0; i < cam->n_sbufs; i++) - vfree(cam->sb_bufs[i].buffer); - cam->n_sbufs = 0; - kfree(cam->sb_bufs); - cam->sb_bufs = NULL; - INIT_LIST_HEAD(&cam->sb_avail); - INIT_LIST_HEAD(&cam->sb_full); - return 0; -} - - - -static int cafe_vidioc_reqbufs(struct file *filp, void *priv, - struct v4l2_requestbuffers *req) -{ - struct cafe_camera *cam = filp->private_data; - int ret = 0; /* Silence warning */ - - /* - * Make sure it's something we can do. User pointers could be - * implemented without great pain, but that's not been done yet. - */ - if (req->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - /* - * If they ask for zero buffers, they really want us to stop streaming - * (if it's happening) and free everything. Should we check owner? - */ - mutex_lock(&cam->s_mutex); - if (req->count == 0) { - if (cam->state == S_STREAMING) - cafe_ctlr_stop_dma(cam); - ret = cafe_free_sio_buffers (cam); - goto out; - } - /* - * Device needs to be idle and working. We *could* try to do the - * right thing in S_SPECREAD by shutting things down, but it - * probably doesn't matter. - */ - if (cam->state != S_IDLE || (cam->owner && cam->owner != filp)) { - ret = -EBUSY; - goto out; - } - cam->owner = filp; - - if (req->count < min_buffers) - req->count = min_buffers; - else if (req->count > max_buffers) - req->count = max_buffers; - if (cam->n_sbufs > 0) { - ret = cafe_free_sio_buffers(cam); - if (ret) - goto out; - } - - cam->sb_bufs = kzalloc(req->count*sizeof(struct cafe_sio_buffer), - GFP_KERNEL); - if (cam->sb_bufs == NULL) { - ret = -ENOMEM; - goto out; - } - for (cam->n_sbufs = 0; cam->n_sbufs < req->count; (cam->n_sbufs++)) { - ret = cafe_setup_siobuf(cam, cam->n_sbufs); - if (ret) - break; - } - - if (cam->n_sbufs == 0) /* no luck at all - ret already set */ - kfree(cam->sb_bufs); - req->count = cam->n_sbufs; /* In case of partial success */ - - out: - mutex_unlock(&cam->s_mutex); - return ret; -} - - -static int cafe_vidioc_querybuf(struct file *filp, void *priv, - struct v4l2_buffer *buf) -{ - struct cafe_camera *cam = filp->private_data; - int ret = -EINVAL; - - mutex_lock(&cam->s_mutex); - if (buf->index >= cam->n_sbufs) - goto out; - *buf = cam->sb_bufs[buf->index].v4lbuf; - ret = 0; - out: - mutex_unlock(&cam->s_mutex); - return ret; -} - -static int cafe_vidioc_qbuf(struct file *filp, void *priv, - struct v4l2_buffer *buf) -{ - struct cafe_camera *cam = filp->private_data; - struct cafe_sio_buffer *sbuf; - int ret = -EINVAL; - unsigned long flags; - - mutex_lock(&cam->s_mutex); - if (buf->index >= cam->n_sbufs) - goto out; - sbuf = cam->sb_bufs + buf->index; - if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) { - ret = 0; /* Already queued?? */ - goto out; - } - if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_DONE) { - /* Spec doesn't say anything, seems appropriate tho */ - ret = -EBUSY; - goto out; - } - sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED; - spin_lock_irqsave(&cam->dev_lock, flags); - list_add(&sbuf->list, &cam->sb_avail); - spin_unlock_irqrestore(&cam->dev_lock, flags); - ret = 0; - out: - mutex_unlock(&cam->s_mutex); - return ret; -} - -static int cafe_vidioc_dqbuf(struct file *filp, void *priv, - struct v4l2_buffer *buf) -{ - struct cafe_camera *cam = filp->private_data; - struct cafe_sio_buffer *sbuf; - int ret = -EINVAL; - unsigned long flags; - - mutex_lock(&cam->s_mutex); - if (cam->state != S_STREAMING) - goto out_unlock; - if (list_empty(&cam->sb_full) && filp->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto out_unlock; - } - - while (list_empty(&cam->sb_full) && cam->state == S_STREAMING) { - mutex_unlock(&cam->s_mutex); - if (wait_event_interruptible(cam->iowait, - !list_empty(&cam->sb_full))) { - ret = -ERESTARTSYS; - goto out; - } - mutex_lock(&cam->s_mutex); - } - - if (cam->state != S_STREAMING) - ret = -EINTR; - else { - spin_lock_irqsave(&cam->dev_lock, flags); - /* Should probably recheck !list_empty() here */ - sbuf = list_entry(cam->sb_full.next, - struct cafe_sio_buffer, list); - list_del_init(&sbuf->list); - spin_unlock_irqrestore(&cam->dev_lock, flags); - sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE; - *buf = sbuf->v4lbuf; - ret = 0; - } - - out_unlock: - mutex_unlock(&cam->s_mutex); - out: - return ret; -} - - - -static void cafe_v4l_vm_open(struct vm_area_struct *vma) -{ - struct cafe_sio_buffer *sbuf = vma->vm_private_data; - /* - * Locking: done under mmap_sem, so we don't need to - * go back to the camera lock here. - */ - sbuf->mapcount++; -} - - -static void cafe_v4l_vm_close(struct vm_area_struct *vma) -{ - struct cafe_sio_buffer *sbuf = vma->vm_private_data; - - mutex_lock(&sbuf->cam->s_mutex); - sbuf->mapcount--; - /* Docs say we should stop I/O too... */ - if (sbuf->mapcount == 0) - sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED; - mutex_unlock(&sbuf->cam->s_mutex); -} - -static const struct vm_operations_struct cafe_v4l_vm_ops = { - .open = cafe_v4l_vm_open, - .close = cafe_v4l_vm_close -}; - - -static int cafe_v4l_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct cafe_camera *cam = filp->private_data; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - int ret = -EINVAL; - int i; - struct cafe_sio_buffer *sbuf = NULL; - - if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED)) - return -EINVAL; - /* - * Find the buffer they are looking for. - */ - mutex_lock(&cam->s_mutex); - for (i = 0; i < cam->n_sbufs; i++) - if (cam->sb_bufs[i].v4lbuf.m.offset == offset) { - sbuf = cam->sb_bufs + i; - break; - } - if (sbuf == NULL) - goto out; - - ret = remap_vmalloc_range(vma, sbuf->buffer, 0); - if (ret) - goto out; - vma->vm_flags |= VM_DONTEXPAND; - vma->vm_private_data = sbuf; - vma->vm_ops = &cafe_v4l_vm_ops; - sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED; - cafe_v4l_vm_open(vma); - ret = 0; - out: - mutex_unlock(&cam->s_mutex); - return ret; -} - - - -static int cafe_v4l_open(struct file *filp) -{ - struct cafe_camera *cam = video_drvdata(filp); - - filp->private_data = cam; - - mutex_lock(&cam->s_mutex); - if (cam->users == 0) { - cafe_ctlr_power_up(cam); - __cafe_cam_reset(cam); - cafe_set_config_needed(cam, 1); - /* FIXME make sure this is complete */ - } - (cam->users)++; - mutex_unlock(&cam->s_mutex); - return 0; -} - - -static int cafe_v4l_release(struct file *filp) -{ - struct cafe_camera *cam = filp->private_data; - - mutex_lock(&cam->s_mutex); - (cam->users)--; - if (filp == cam->owner) { - cafe_ctlr_stop_dma(cam); - cafe_free_sio_buffers(cam); - cam->owner = NULL; - } - if (cam->users == 0) { - cafe_ctlr_power_down(cam); - if (alloc_bufs_at_read) - cafe_free_dma_bufs(cam); - } - mutex_unlock(&cam->s_mutex); - return 0; -} - - - -static unsigned int cafe_v4l_poll(struct file *filp, - struct poll_table_struct *pt) -{ - struct cafe_camera *cam = filp->private_data; - - poll_wait(filp, &cam->iowait, pt); - if (cam->next_buf >= 0) - return POLLIN | POLLRDNORM; - return 0; -} - - - -static int cafe_vidioc_queryctrl(struct file *filp, void *priv, - struct v4l2_queryctrl *qc) -{ - struct cafe_camera *cam = priv; - int ret; - - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, core, queryctrl, qc); - mutex_unlock(&cam->s_mutex); - return ret; -} - - -static int cafe_vidioc_g_ctrl(struct file *filp, void *priv, - struct v4l2_control *ctrl) -{ - struct cafe_camera *cam = priv; - int ret; - - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, core, g_ctrl, ctrl); - mutex_unlock(&cam->s_mutex); - return ret; -} - - -static int cafe_vidioc_s_ctrl(struct file *filp, void *priv, - struct v4l2_control *ctrl) -{ - struct cafe_camera *cam = priv; - int ret; - - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, core, s_ctrl, ctrl); - mutex_unlock(&cam->s_mutex); - return ret; -} - - - - - -static int cafe_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - strcpy(cap->driver, "cafe_ccic"); - strcpy(cap->card, "cafe_ccic"); - cap->version = CAFE_VERSION; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - return 0; -} - - -/* - * The default format we use until somebody says otherwise. - */ -static const struct v4l2_pix_format cafe_def_pix_format = { - .width = VGA_WIDTH, - .height = VGA_HEIGHT, - .pixelformat = V4L2_PIX_FMT_YUYV, - .field = V4L2_FIELD_NONE, - .bytesperline = VGA_WIDTH*2, - .sizeimage = VGA_WIDTH*VGA_HEIGHT*2, -}; - -static const enum v4l2_mbus_pixelcode cafe_def_mbus_code = - V4L2_MBUS_FMT_YUYV8_2X8; - -static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp, - void *priv, struct v4l2_fmtdesc *fmt) -{ - if (fmt->index >= N_CAFE_FMTS) - return -EINVAL; - strlcpy(fmt->description, cafe_formats[fmt->index].desc, - sizeof(fmt->description)); - fmt->pixelformat = cafe_formats[fmt->index].pixelformat; - return 0; -} - -static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv, - struct v4l2_format *fmt) -{ - struct cafe_camera *cam = priv; - struct cafe_format_struct *f; - struct v4l2_pix_format *pix = &fmt->fmt.pix; - struct v4l2_mbus_framefmt mbus_fmt; - int ret; - - f = cafe_find_format(pix->pixelformat); - pix->pixelformat = f->pixelformat; - v4l2_fill_mbus_format(&mbus_fmt, pix, f->mbus_code); - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt); - mutex_unlock(&cam->s_mutex); - v4l2_fill_pix_format(pix, &mbus_fmt); - pix->bytesperline = pix->width * f->bpp; - pix->sizeimage = pix->height * pix->bytesperline; - return ret; -} - -static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv, - struct v4l2_format *fmt) -{ - struct cafe_camera *cam = priv; - struct cafe_format_struct *f; - int ret; - - /* - * Can't do anything if the device is not idle - * Also can't if there are streaming buffers in place. - */ - if (cam->state != S_IDLE || cam->n_sbufs > 0) - return -EBUSY; - - f = cafe_find_format(fmt->fmt.pix.pixelformat); - - /* - * See if the formatting works in principle. - */ - ret = cafe_vidioc_try_fmt_vid_cap(filp, priv, fmt); - if (ret) - return ret; - /* - * Now we start to change things for real, so let's do it - * under lock. - */ - mutex_lock(&cam->s_mutex); - cam->pix_format = fmt->fmt.pix; - cam->mbus_code = f->mbus_code; - - /* - * Make sure we have appropriate DMA buffers. - */ - ret = -ENOMEM; - if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage) - cafe_free_dma_bufs(cam); - if (cam->nbufs == 0) { - if (cafe_alloc_dma_bufs(cam, 0)) - goto out; - } - /* - * It looks like this might work, so let's program the sensor. - */ - ret = cafe_cam_configure(cam); - if (! ret) - ret = cafe_ctlr_configure(cam); - out: - mutex_unlock(&cam->s_mutex); - return ret; -} - -/* - * Return our stored notion of how the camera is/should be configured. - * The V4l2 spec wants us to be smarter, and actually get this from - * the camera (and not mess with it at open time). Someday. - */ -static int cafe_vidioc_g_fmt_vid_cap(struct file *filp, void *priv, - struct v4l2_format *f) -{ - struct cafe_camera *cam = priv; - - f->fmt.pix = cam->pix_format; - return 0; -} - -/* - * We only have one input - the sensor - so minimize the nonsense here. - */ -static int cafe_vidioc_enum_input(struct file *filp, void *priv, - struct v4l2_input *input) -{ - if (input->index != 0) - return -EINVAL; - - input->type = V4L2_INPUT_TYPE_CAMERA; - input->std = V4L2_STD_ALL; /* Not sure what should go here */ - strcpy(input->name, "Camera"); - return 0; -} - -static int cafe_vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int cafe_vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; -} - -/* from vivi.c */ -static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a) -{ - return 0; -} - -/* - * G/S_PARM. Most of this is done by the sensor, but we are - * the level which controls the number of read buffers. - */ -static int cafe_vidioc_g_parm(struct file *filp, void *priv, - struct v4l2_streamparm *parms) -{ - struct cafe_camera *cam = priv; - int ret; - - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, video, g_parm, parms); - mutex_unlock(&cam->s_mutex); - parms->parm.capture.readbuffers = n_dma_bufs; - return ret; -} - -static int cafe_vidioc_s_parm(struct file *filp, void *priv, - struct v4l2_streamparm *parms) -{ - struct cafe_camera *cam = priv; - int ret; - - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, video, s_parm, parms); - mutex_unlock(&cam->s_mutex); - parms->parm.capture.readbuffers = n_dma_bufs; - return ret; -} - -static int cafe_vidioc_g_chip_ident(struct file *file, void *priv, - struct v4l2_dbg_chip_ident *chip) -{ - struct cafe_camera *cam = priv; - - chip->ident = V4L2_IDENT_NONE; - chip->revision = 0; - if (v4l2_chip_match_host(&chip->match)) { - chip->ident = V4L2_IDENT_CAFE; - return 0; - } - return sensor_call(cam, core, g_chip_ident, chip); -} - -static int cafe_vidioc_enum_framesizes(struct file *filp, void *priv, - struct v4l2_frmsizeenum *sizes) -{ - struct cafe_camera *cam = priv; - int ret; - - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, video, enum_framesizes, sizes); - mutex_unlock(&cam->s_mutex); - return ret; -} - -static int cafe_vidioc_enum_frameintervals(struct file *filp, void *priv, - struct v4l2_frmivalenum *interval) -{ - struct cafe_camera *cam = priv; - int ret; - - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, video, enum_frameintervals, interval); - mutex_unlock(&cam->s_mutex); - return ret; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int cafe_vidioc_g_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) -{ - struct cafe_camera *cam = priv; - - if (v4l2_chip_match_host(®->match)) { - reg->val = cafe_reg_read(cam, reg->reg); - reg->size = 4; - return 0; - } - return sensor_call(cam, core, g_register, reg); -} - -static int cafe_vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) -{ - struct cafe_camera *cam = priv; - - if (v4l2_chip_match_host(®->match)) { - cafe_reg_write(cam, reg->reg, reg->val); - return 0; - } - return sensor_call(cam, core, s_register, reg); -} -#endif - -/* - * This template device holds all of those v4l2 methods; we - * clone it for specific real devices. - */ - -static const struct v4l2_file_operations cafe_v4l_fops = { - .owner = THIS_MODULE, - .open = cafe_v4l_open, - .release = cafe_v4l_release, - .read = cafe_v4l_read, - .poll = cafe_v4l_poll, - .mmap = cafe_v4l_mmap, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = { - .vidioc_querycap = cafe_vidioc_querycap, - .vidioc_enum_fmt_vid_cap = cafe_vidioc_enum_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = cafe_vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = cafe_vidioc_s_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = cafe_vidioc_g_fmt_vid_cap, - .vidioc_enum_input = cafe_vidioc_enum_input, - .vidioc_g_input = cafe_vidioc_g_input, - .vidioc_s_input = cafe_vidioc_s_input, - .vidioc_s_std = cafe_vidioc_s_std, - .vidioc_reqbufs = cafe_vidioc_reqbufs, - .vidioc_querybuf = cafe_vidioc_querybuf, - .vidioc_qbuf = cafe_vidioc_qbuf, - .vidioc_dqbuf = cafe_vidioc_dqbuf, - .vidioc_streamon = cafe_vidioc_streamon, - .vidioc_streamoff = cafe_vidioc_streamoff, - .vidioc_queryctrl = cafe_vidioc_queryctrl, - .vidioc_g_ctrl = cafe_vidioc_g_ctrl, - .vidioc_s_ctrl = cafe_vidioc_s_ctrl, - .vidioc_g_parm = cafe_vidioc_g_parm, - .vidioc_s_parm = cafe_vidioc_s_parm, - .vidioc_enum_framesizes = cafe_vidioc_enum_framesizes, - .vidioc_enum_frameintervals = cafe_vidioc_enum_frameintervals, - .vidioc_g_chip_ident = cafe_vidioc_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = cafe_vidioc_g_register, - .vidioc_s_register = cafe_vidioc_s_register, -#endif -}; - -static struct video_device cafe_v4l_template = { - .name = "cafe", - .tvnorms = V4L2_STD_NTSC_M, - .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */ - - .fops = &cafe_v4l_fops, - .ioctl_ops = &cafe_v4l_ioctl_ops, - .release = video_device_release_empty, -}; - - -/* ---------------------------------------------------------------------- */ -/* - * Interrupt handler stuff - */ - - - -static void cafe_frame_tasklet(unsigned long data) -{ - struct cafe_camera *cam = (struct cafe_camera *) data; - int i; - unsigned long flags; - struct cafe_sio_buffer *sbuf; - - spin_lock_irqsave(&cam->dev_lock, flags); - for (i = 0; i < cam->nbufs; i++) { - int bufno = cam->next_buf; - if (bufno < 0) { /* "will never happen" */ - cam_err(cam, "No valid bufs in tasklet!\n"); - break; - } - if (++(cam->next_buf) >= cam->nbufs) - cam->next_buf = 0; - if (! test_bit(bufno, &cam->flags)) - continue; - if (list_empty(&cam->sb_avail)) - break; /* Leave it valid, hope for better later */ - clear_bit(bufno, &cam->flags); - sbuf = list_entry(cam->sb_avail.next, - struct cafe_sio_buffer, list); - /* - * Drop the lock during the big copy. This *should* be safe... - */ - spin_unlock_irqrestore(&cam->dev_lock, flags); - memcpy(sbuf->buffer, cam->dma_bufs[bufno], - cam->pix_format.sizeimage); - sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage; - sbuf->v4lbuf.sequence = cam->buf_seq[bufno]; - sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; - sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; - spin_lock_irqsave(&cam->dev_lock, flags); - list_move_tail(&sbuf->list, &cam->sb_full); - } - if (! list_empty(&cam->sb_full)) - wake_up(&cam->iowait); - spin_unlock_irqrestore(&cam->dev_lock, flags); -} - - - -static void cafe_frame_complete(struct cafe_camera *cam, int frame) -{ - /* - * Basic frame housekeeping. - */ - if (test_bit(frame, &cam->flags) && printk_ratelimit()) - cam_err(cam, "Frame overrun on %d, frames lost\n", frame); - set_bit(frame, &cam->flags); - clear_bit(CF_DMA_ACTIVE, &cam->flags); - if (cam->next_buf < 0) - cam->next_buf = frame; - cam->buf_seq[frame] = ++(cam->sequence); - - switch (cam->state) { - /* - * If in single read mode, try going speculative. - */ - case S_SINGLEREAD: - cam->state = S_SPECREAD; - cam->specframes = 0; - wake_up(&cam->iowait); - break; - - /* - * If we are already doing speculative reads, and nobody is - * reading them, just stop. - */ - case S_SPECREAD: - if (++(cam->specframes) >= cam->nbufs) { - cafe_ctlr_stop(cam); - cafe_ctlr_irq_disable(cam); - cam->state = S_IDLE; - } - wake_up(&cam->iowait); - break; - /* - * For the streaming case, we defer the real work to the - * camera tasklet. - * - * FIXME: if the application is not consuming the buffers, - * we should eventually put things on hold and restart in - * vidioc_dqbuf(). - */ - case S_STREAMING: - tasklet_schedule(&cam->s_tasklet); - break; - - default: - cam_err(cam, "Frame interrupt in non-operational state\n"); - break; - } -} - - - - -static void cafe_frame_irq(struct cafe_camera *cam, unsigned int irqs) -{ - unsigned int frame; - - cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */ - /* - * Handle any frame completions. There really should - * not be more than one of these, or we have fallen - * far behind. - */ - for (frame = 0; frame < cam->nbufs; frame++) - if (irqs & (IRQ_EOF0 << frame)) - cafe_frame_complete(cam, frame); - /* - * If a frame starts, note that we have DMA active. This - * code assumes that we won't get multiple frame interrupts - * at once; may want to rethink that. - */ - if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2)) - set_bit(CF_DMA_ACTIVE, &cam->flags); -} - - - -static irqreturn_t cafe_irq(int irq, void *data) -{ - struct cafe_camera *cam = data; - unsigned int irqs; - - spin_lock(&cam->dev_lock); - irqs = cafe_reg_read(cam, REG_IRQSTAT); - if ((irqs & ALLIRQS) == 0) { - spin_unlock(&cam->dev_lock); - return IRQ_NONE; - } - if (irqs & FRAMEIRQS) - cafe_frame_irq(cam, irqs); - if (irqs & TWSIIRQS) { - cafe_reg_write(cam, REG_IRQSTAT, TWSIIRQS); - wake_up(&cam->smbus_wait); - } - spin_unlock(&cam->dev_lock); - return IRQ_HANDLED; -} - - -/* -------------------------------------------------------------------------- */ -/* - * PCI interface stuff. - */ - -static const struct dmi_system_id olpc_xo1_dmi[] = { - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "OLPC"), - DMI_MATCH(DMI_PRODUCT_NAME, "XO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "1"), - }, - }, - { } -}; - -static int cafe_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - int ret; - struct cafe_camera *cam; - struct ov7670_config sensor_cfg = { - /* This controller only does SMBUS */ - .use_smbus = true, - - /* - * Exclude QCIF mode, because it only captures a tiny portion - * of the sensor FOV - */ - .min_width = 320, - .min_height = 240, - }; - struct i2c_board_info ov7670_info = { - .type = "ov7670", - .addr = 0x42, - .platform_data = &sensor_cfg, - }; - - /* - * Start putting together one of our big camera structures. - */ - ret = -ENOMEM; - cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL); - if (cam == NULL) - goto out; - ret = v4l2_device_register(&pdev->dev, &cam->v4l2_dev); - if (ret) - goto out_free; - - mutex_init(&cam->s_mutex); - spin_lock_init(&cam->dev_lock); - cam->state = S_NOTREADY; - cafe_set_config_needed(cam, 1); - init_waitqueue_head(&cam->smbus_wait); - init_waitqueue_head(&cam->iowait); - cam->pdev = pdev; - cam->pix_format = cafe_def_pix_format; - cam->mbus_code = cafe_def_mbus_code; - INIT_LIST_HEAD(&cam->dev_list); - INIT_LIST_HEAD(&cam->sb_avail); - INIT_LIST_HEAD(&cam->sb_full); - tasklet_init(&cam->s_tasklet, cafe_frame_tasklet, (unsigned long) cam); - /* - * Get set up on the PCI bus. - */ - ret = pci_enable_device(pdev); - if (ret) - goto out_unreg; - pci_set_master(pdev); - - ret = -EIO; - cam->regs = pci_iomap(pdev, 0, 0); - if (! cam->regs) { - printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n"); - goto out_unreg; - } - ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam); - if (ret) - goto out_iounmap; - /* - * Initialize the controller and leave it powered up. It will - * stay that way until the sensor driver shows up. - */ - cafe_ctlr_init(cam); - cafe_ctlr_power_up(cam); - /* - * Set up I2C/SMBUS communications. We have to drop the mutex here - * because the sensor could attach in this call chain, leading to - * unsightly deadlocks. - */ - ret = cafe_smbus_setup(cam); - if (ret) - goto out_freeirq; - - /* Apply XO-1 clock speed */ - if (dmi_check_system(olpc_xo1_dmi)) - sensor_cfg.clock_speed = 45; - - cam->sensor_addr = ov7670_info.addr; - cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, &cam->i2c_adapter, - &ov7670_info, NULL); - if (cam->sensor == NULL) { - ret = -ENODEV; - goto out_smbus; - } - - ret = cafe_cam_init(cam); - if (ret) - goto out_smbus; - - /* - * Get the v4l2 setup done. - */ - mutex_lock(&cam->s_mutex); - cam->vdev = cafe_v4l_template; - cam->vdev.debug = 0; -/* cam->vdev.debug = V4L2_DEBUG_IOCTL_ARG;*/ - cam->vdev.v4l2_dev = &cam->v4l2_dev; - ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); - if (ret) - goto out_unlock; - video_set_drvdata(&cam->vdev, cam); - - /* - * If so requested, try to get our DMA buffers now. - */ - if (!alloc_bufs_at_read) { - if (cafe_alloc_dma_bufs(cam, 1)) - cam_warn(cam, "Unable to alloc DMA buffers at load" - " will try again later."); - } - - mutex_unlock(&cam->s_mutex); - return 0; - -out_unlock: - mutex_unlock(&cam->s_mutex); -out_smbus: - cafe_smbus_shutdown(cam); -out_freeirq: - cafe_ctlr_power_down(cam); - free_irq(pdev->irq, cam); -out_iounmap: - pci_iounmap(pdev, cam->regs); -out_free: - v4l2_device_unregister(&cam->v4l2_dev); -out_unreg: - kfree(cam); -out: - return ret; -} - - -/* - * Shut down an initialized device - */ -static void cafe_shutdown(struct cafe_camera *cam) -{ -/* FIXME: Make sure we take care of everything here */ - if (cam->n_sbufs > 0) - /* What if they are still mapped? Shouldn't be, but... */ - cafe_free_sio_buffers(cam); - cafe_ctlr_stop_dma(cam); - cafe_ctlr_power_down(cam); - cafe_smbus_shutdown(cam); - cafe_free_dma_bufs(cam); - free_irq(cam->pdev->irq, cam); - pci_iounmap(cam->pdev, cam->regs); - video_unregister_device(&cam->vdev); -} - - -static void cafe_pci_remove(struct pci_dev *pdev) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); - struct cafe_camera *cam = to_cam(v4l2_dev); - - if (cam == NULL) { - printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev); - return; - } - mutex_lock(&cam->s_mutex); - if (cam->users > 0) - cam_warn(cam, "Removing a device with users!\n"); - cafe_shutdown(cam); - v4l2_device_unregister(&cam->v4l2_dev); - kfree(cam); -/* No unlock - it no longer exists */ -} - - -#ifdef CONFIG_PM -/* - * Basic power management. - */ -static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); - struct cafe_camera *cam = to_cam(v4l2_dev); - int ret; - enum cafe_state cstate; - - ret = pci_save_state(pdev); - if (ret) - return ret; - cstate = cam->state; /* HACK - stop_dma sets to idle */ - cafe_ctlr_stop_dma(cam); - cafe_ctlr_power_down(cam); - pci_disable_device(pdev); - cam->state = cstate; - return 0; -} - - -static int cafe_pci_resume(struct pci_dev *pdev) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); - struct cafe_camera *cam = to_cam(v4l2_dev); - int ret = 0; - - pci_restore_state(pdev); - ret = pci_enable_device(pdev); - - if (ret) { - cam_warn(cam, "Unable to re-enable device on resume!\n"); - return ret; - } - cafe_ctlr_init(cam); - - mutex_lock(&cam->s_mutex); - if (cam->users > 0) { - cafe_ctlr_power_up(cam); - __cafe_cam_reset(cam); - } else { - cafe_ctlr_power_down(cam); - } - mutex_unlock(&cam->s_mutex); - - set_bit(CF_CONFIG_NEEDED, &cam->flags); - if (cam->state == S_SPECREAD) - cam->state = S_IDLE; /* Don't bother restarting */ - else if (cam->state == S_SINGLEREAD || cam->state == S_STREAMING) - ret = cafe_read_setup(cam, cam->state); - return ret; -} - -#endif /* CONFIG_PM */ - - -static struct pci_device_id cafe_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, - PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, cafe_ids); - -static struct pci_driver cafe_pci_driver = { - .name = "cafe1000-ccic", - .id_table = cafe_ids, - .probe = cafe_pci_probe, - .remove = cafe_pci_remove, -#ifdef CONFIG_PM - .suspend = cafe_pci_suspend, - .resume = cafe_pci_resume, -#endif -}; - - - - -static int __init cafe_init(void) -{ - int ret; - - printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n", - CAFE_VERSION); - ret = pci_register_driver(&cafe_pci_driver); - if (ret) { - printk(KERN_ERR "Unable to register cafe_ccic driver\n"); - goto out; - } - ret = 0; - - out: - return ret; -} - - -static void __exit cafe_exit(void) -{ - pci_unregister_driver(&cafe_pci_driver); -} - -module_init(cafe_init); -module_exit(cafe_exit); diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h index 6d6d1843791ce0a7ef880211b33f92c85bee4922..ab252188981b688605f8dd1c852bce9422b09122 100644 --- a/drivers/media/video/cpia2/cpia2.h +++ b/drivers/media/video/cpia2/cpia2.h @@ -31,7 +31,6 @@ #ifndef __CPIA2_H__ #define __CPIA2_H__ -#include #include #include #include @@ -43,10 +42,6 @@ /* define for verbose debug output */ //#define _CPIA2_DEBUG_ -#define CPIA2_MAJ_VER 3 -#define CPIA2_MIN_VER 0 -#define CPIA2_PATCH_VER 0 - /*** * Image defines ***/ diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 40eb6326e48a8ab95ca7c476999772bd3e76ff3b..077eb1db80a1b4d926c77cac24c979ab255982a0 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -29,8 +29,7 @@ * Alan Cox ****************************************************************************/ -#include - +#define CPIA_VERSION "3.0.1" #include #include @@ -80,6 +79,7 @@ MODULE_AUTHOR("Steve Miller (STMicroelectronics) "); MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras"); MODULE_SUPPORTED_DEVICE("video"); MODULE_LICENSE("GPL"); +MODULE_VERSION(CPIA_VERSION); #define ABOUT "V4L-Driver for Vision CPiA2 based cameras" @@ -465,9 +465,6 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0) memset(vc->bus_info,0, sizeof(vc->bus_info)); - vc->version = KERNEL_VERSION(CPIA2_MAJ_VER, CPIA2_MIN_VER, - CPIA2_PATCH_VER); - vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; @@ -1558,8 +1555,8 @@ static void __init check_parameters(void) *****************************************************************************/ static int __init cpia2_init(void) { - LOG("%s v%d.%d.%d\n", - ABOUT, CPIA2_MAJ_VER, CPIA2_MIN_VER, CPIA2_PATCH_VER); + LOG("%s v%s\n", + ABOUT, CPIA_VERSION); check_parameters(); cpia2_usb_init(); return 0; @@ -1579,4 +1576,3 @@ static void __exit cpia2_exit(void) module_init(cpia2_init); module_exit(cpia2_exit); - diff --git a/drivers/media/video/cx18/cx18-alsa-main.c b/drivers/media/video/cx18/cx18-alsa-main.c index d50d69da387b5d0ea30fb6be335c7fb23523e55b..a1e6c2a32478225ef0860f61ea1688f723ab2443 100644 --- a/drivers/media/video/cx18/cx18-alsa-main.c +++ b/drivers/media/video/cx18/cx18-alsa-main.c @@ -192,6 +192,7 @@ static int snd_cx18_init(struct v4l2_device *v4l2_dev) err_exit_free: if (sc != NULL) snd_card_free(sc); + kfree(cxsc); err_exit: return ret; } diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index 086427288de80417ced9c1a23299f7f2623bda06..1834207230607a5ce714ce1492b6855bb56bed44 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h @@ -25,7 +25,6 @@ #ifndef CX18_DRIVER_H #define CX18_DRIVER_H -#include #include #include #include diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index e80134f52ef5c3ba41b00a4d3751d4ba95db3365..afe0a29e7200b9cdbb21447f7f0d7a5256ed0c8f 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -469,7 +469,6 @@ static int cx18_querycap(struct file *file, void *fh, strlcpy(vcap->card, cx->card_name, sizeof(vcap->card)); snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(cx->pci_dev)); - vcap->version = CX18_DRIVER_VERSION; /* version */ vcap->capabilities = cx->v4l2_cap; /* capabilities */ return 0; } diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h index cd189b6bbe208ce401e0b596426b6215f783a612..fed48b6bb67b622b981532be129a5834ecdd8547 100644 --- a/drivers/media/video/cx18/cx18-version.h +++ b/drivers/media/video/cx18/cx18-version.h @@ -23,12 +23,6 @@ #define CX18_VERSION_H #define CX18_DRIVER_NAME "cx18" -#define CX18_DRIVER_VERSION_MAJOR 1 -#define CX18_DRIVER_VERSION_MINOR 5 -#define CX18_DRIVER_VERSION_PATCHLEVEL 0 - -#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) -#define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \ - CX18_DRIVER_VERSION_MINOR, CX18_DRIVER_VERSION_PATCHLEVEL) +#define CX18_VERSION "1.5.1" #endif diff --git a/drivers/media/video/cx231xx/cx231xx-avcore.c b/drivers/media/video/cx231xx/cx231xx-avcore.c index 8d7813415760e5f1cf753368f86b0f124e642b55..53ff26e7abf77036136b60f2a5520e41623fbd14 100644 --- a/drivers/media/video/cx231xx/cx231xx-avcore.c +++ b/drivers/media/video/cx231xx/cx231xx-avcore.c @@ -355,6 +355,8 @@ int cx231xx_afe_update_power_control(struct cx231xx *dev, case CX231XX_BOARD_HAUPPAUGE_EXETER: case CX231XX_BOARD_HAUPPAUGE_USBLIVE2: case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC: if (avmode == POLARIS_AVMODE_ANALOGT_TV) { while (afe_power_status != (FLD_PWRDN_TUNING_BIAS | FLD_PWRDN_ENABLE_PLL)) { @@ -1733,6 +1735,8 @@ int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard) break; case CX231XX_BOARD_CNXT_RDE_253S: case CX231XX_BOARD_CNXT_RDU_253S: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC: func_mode = 0x01; break; default: diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index 22703815a31fdfa506c6f8a6a72866dee907d1a7..53dae2a8272dc60569e8056803a436295175cd20 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c @@ -387,6 +387,7 @@ struct cx231xx_board cx231xx_boards[] = { .norm = V4L2_STD_NTSC, .no_alt_vanc = 1, .external_av = 1, + .dont_use_port_3 = 1, .input = {{ .type = CX231XX_VMUX_COMPOSITE1, .vmux = CX231XX_VIN_2_1, @@ -532,6 +533,76 @@ struct cx231xx_board cx231xx_boards[] = { .gpio = NULL, } }, }, + [CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL] = { + .name = "Hauppauge WinTV USB2 FM (PAL)", + .tuner_type = TUNER_NXP_TDA18271, + .tuner_addr = 0x60, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = 1, + .norm = V4L2_STD_PAL, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, + [CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC] = { + .name = "Hauppauge WinTV USB2 FM (NTSC)", + .tuner_type = TUNER_NXP_TDA18271, + .tuner_addr = 0x60, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = 1, + .norm = V4L2_STD_NTSC, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, }; const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); @@ -553,6 +624,10 @@ struct usb_device_id cx231xx_id_table[] = { .driver_info = CX231XX_BOARD_CNXT_RDE_250}, {USB_DEVICE(0x0572, 0x58A0), .driver_info = CX231XX_BOARD_CNXT_RDU_250}, + {USB_DEVICE(0x2040, 0xb110), + .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL}, + {USB_DEVICE(0x2040, 0xb111), + .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC}, {USB_DEVICE(0x2040, 0xb120), .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER}, {USB_DEVICE(0x2040, 0xb140), @@ -1051,6 +1126,9 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (assoc_desc->bFirstInterface != ifnum) { cx231xx_err(DRIVER_NAME ": Not found " "matching IAD interface\n"); + cx231xx_devused &= ~(1 << nr); + kfree(dev); + dev = NULL; return -ENODEV; } diff --git a/drivers/media/video/cx231xx/cx231xx-core.c b/drivers/media/video/cx231xx/cx231xx-core.c index abe500feb7dd8adad785380eaa1a86ad4b5d5440..d4457f9488eee6c6e06feb1dd7c7ef727d6b91b8 100644 --- a/drivers/media/video/cx231xx/cx231xx-core.c +++ b/drivers/media/video/cx231xx/cx231xx-core.c @@ -742,6 +742,8 @@ int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode) case CX231XX_BOARD_CNXT_RDU_253S: case CX231XX_BOARD_HAUPPAUGE_EXETER: case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC: errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0); break; default: @@ -1381,6 +1383,8 @@ int cx231xx_dev_init(struct cx231xx *dev) case CX231XX_BOARD_CNXT_RDU_253S: case CX231XX_BOARD_HAUPPAUGE_EXETER: case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC: errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0); break; default: diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c index a69c24d8db060c93f41f2085212304220de0a462..6e81f970dc7d8e35d48975e141c5e75fbfdf878f 100644 --- a/drivers/media/video/cx231xx/cx231xx-video.c +++ b/drivers/media/video/cx231xx/cx231xx-video.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -45,7 +44,7 @@ #include "cx231xx.h" #include "cx231xx-vbi.h" -#define CX231XX_VERSION_CODE KERNEL_VERSION(0, 0, 1) +#define CX231XX_VERSION "0.0.2" #define DRIVER_AUTHOR "Srinivasa Deevi " #define DRIVER_DESC "Conexant cx231xx based USB video device driver" @@ -70,6 +69,7 @@ do {\ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); +MODULE_VERSION(CX231XX_VERSION); static unsigned int card[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET }; static unsigned int video_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET }; @@ -1179,7 +1179,8 @@ static int vidioc_enum_input(struct file *file, void *priv, { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; - unsigned int n; + u32 gen_stat; + unsigned int ret, n; n = i->index; if (n >= MAX_CX231XX_INPUT) @@ -1198,6 +1199,18 @@ static int vidioc_enum_input(struct file *file, void *priv, i->std = dev->vdev->tvnorms; + /* If they are asking about the active input, read signal status */ + if (n == dev->video_input) { + ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS, + GEN_STAT, 2, &gen_stat, 4); + if (ret > 0) { + if ((gen_stat & FLD_VPRES) == 0x00) + i->status |= V4L2_IN_ST_NO_SIGNAL; + if ((gen_stat & FLD_HLOCK) == 0x00) + i->status |= V4L2_IN_ST_NO_H_LOCK; + } + } + return 0; } @@ -1869,8 +1882,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->version = CX231XX_VERSION_CODE; - cap->capabilities = V4L2_CAP_VBI_CAPTURE | #if 0 V4L2_CAP_SLICED_VBI_CAPTURE | @@ -2057,7 +2068,6 @@ static int radio_querycap(struct file *file, void *priv, strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->version = CX231XX_VERSION_CODE; cap->capabilities = V4L2_CAP_TUNER; return 0; } @@ -2570,11 +2580,8 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) { int ret; - cx231xx_info("%s: v4l2 driver version %d.%d.%d\n", - dev->name, - (CX231XX_VERSION_CODE >> 16) & 0xff, - (CX231XX_VERSION_CODE >> 8) & 0xff, - CX231XX_VERSION_CODE & 0xff); + cx231xx_info("%s: v4l2 driver version %s\n", + dev->name, CX231XX_VERSION); /* set default norm */ /*dev->norm = cx231xx_video_template.current_norm; */ diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h index 46dd8406781695d50d1855dabe5af90565ad89bd..2000bc64c49784af168855f9dfab150b078a6d48 100644 --- a/drivers/media/video/cx231xx/cx231xx.h +++ b/drivers/media/video/cx231xx/cx231xx.h @@ -43,7 +43,7 @@ #include "cx231xx-conf-reg.h" #define DRIVER_NAME "cx231xx" -#define PWR_SLEEP_INTERVAL 5 +#define PWR_SLEEP_INTERVAL 10 /* I2C addresses for control block in Cx231xx */ #define AFE_DEVICE_ADDRESS 0x60 @@ -67,6 +67,8 @@ #define CX231XX_BOARD_PV_XCAPTURE_USB 11 #define CX231XX_BOARD_KWORLD_UB430_USB_HYBRID 12 #define CX231XX_BOARD_ICONBIT_U100 13 +#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL 14 +#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC 15 /* Limits minimum and default number of buffers */ #define CX231XX_MIN_BUF 4 @@ -112,7 +114,6 @@ V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \ V4L2_STD_PAL_60 | V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK) -#define CX231xx_VERSION_CODE KERNEL_VERSION(0, 0, 2) #define SLEEP_S5H1432 30 #define CX23417_OSC_EN 8 diff --git a/drivers/media/video/cx23885/altera-ci.c b/drivers/media/video/cx23885/altera-ci.c index 678539b2acfa70dde346378c47332abaf857f5fd..1fa8927f0d36eecb3946b7c7c48467eb3d540640 100644 --- a/drivers/media/video/cx23885/altera-ci.c +++ b/drivers/media/video/cx23885/altera-ci.c @@ -52,7 +52,6 @@ * | DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0| * +-------+-------+-------+-------+-------+-------+-------+-------+ */ -#include #include #include #include "altera-ci.h" diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 9a98dc55f6572fac82e0c6e0936d1af8a03218d9..67c4a59bd8825800cda0bd1e657c92673ab4c944 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -1359,7 +1359,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, cx23885_boards[tsport->dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->version = CX23885_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 934185cca758d7461e3bc96bead9f64db90625c0..76b7563de39c9eadec8a492a7e01ad77138e776c 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -29,11 +29,17 @@ #include "../../../staging/altera-stapl/altera.h" #include "cx23885.h" #include "tuner-xc2028.h" +#include "netup-eeprom.h" #include "netup-init.h" #include "altera-ci.h" +#include "xc4000.h" #include "xc5000.h" #include "cx23888-ir.h" +static unsigned int netup_card_rev = 1; +module_param(netup_card_rev, int, 0644); +MODULE_PARM_DESC(netup_card_rev, + "NetUP Dual DVB-T/C CI card revision"); static unsigned int enable_885_ir; module_param(enable_885_ir, int, 0644); MODULE_PARM_DESC(enable_885_ir, @@ -175,6 +181,34 @@ struct cx23885_board cx23885_boards[] = { .name = "Leadtek Winfast PxDVR3200 H", .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000] = { + .name = "Leadtek Winfast PxDVR3200 H XC4000", + .porta = CX23885_ANALOG_VIDEO, + .portc = CX23885_MPEG_DVB, + .tuner_type = TUNER_XC4000, + .tuner_addr = 0x61, + .radio_type = TUNER_XC4000, + .radio_addr = 0x61, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_VIN2_CH1 | + CX25840_VIN5_CH2 | + CX25840_NONE0_CH3, + }, { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_COMPOSITE1, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_SVIDEO_LUMA3 | + CX25840_SVIDEO_CHROMA4, + }, { + .type = CX23885_VMUX_COMPONENT, + .vmux = CX25840_VIN7_CH1 | + CX25840_VIN6_CH2 | + CX25840_VIN8_CH3 | + CX25840_COMPONENT_ON, + } }, + }, [CX23885_BOARD_COMPRO_VIDEOMATE_E650F] = { .name = "Compro VideoMate E650F", .portc = CX23885_MPEG_DVB, @@ -432,6 +466,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x107d, .subdevice = 0x6681, .card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H, + }, { + .subvendor = 0x107d, + .subdevice = 0x6f39, + .card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000, }, { .subvendor = 0x185b, .subdevice = 0xe800, @@ -749,6 +787,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg) case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: case CX23885_BOARD_COMPRO_VIDEOMATE_E800: case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: @@ -909,6 +948,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) cx_set(GP0_IO, 0x000f000f); break; case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: case CX23885_BOARD_COMPRO_VIDEOMATE_E800: case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: @@ -1097,12 +1137,19 @@ int cx23885_ir_init(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1200: case CX23885_BOARD_HAUPPAUGE_HVR1400: - case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1275: case CX23885_BOARD_HAUPPAUGE_HVR1255: case CX23885_BOARD_HAUPPAUGE_HVR1210: /* FIXME: Implement me */ break; + case CX23885_BOARD_HAUPPAUGE_HVR1270: + ret = cx23888_ir_probe(dev); + if (ret) + break; + dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR); + v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, + ir_rx_pin_cfg_count, ir_rx_pin_cfg); + break; case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: ret = cx23888_ir_probe(dev); @@ -1156,6 +1203,7 @@ int cx23885_ir_init(struct cx23885_dev *dev) void cx23885_ir_fini(struct cx23885_dev *dev) { switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: cx23885_irq_remove(dev, PCI_MSK_IR); @@ -1199,6 +1247,7 @@ int netup_jtag_io(void *device, int tms, int tdi, int read_tdo) void cx23885_ir_pci_int_enable(struct cx23885_dev *dev) { switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: if (dev->sd_ir) @@ -1325,6 +1374,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1700: case CX23885_BOARD_HAUPPAUGE_HVR1400: case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1275: @@ -1353,10 +1403,12 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1800lp: case CX23885_BOARD_HAUPPAUGE_HVR1700: case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: case CX23885_BOARD_COMPRO_VIDEOMATE_E800: + case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_MYGICA_X8506: case CX23885_BOARD_MAGICPRO_PROHDTVE2: @@ -1383,6 +1435,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) const struct firmware *fw; const char *filename = "dvb-netup-altera-01.fw"; char *action = "configure"; + static struct netup_card_info cinfo; struct altera_config netup_config = { .dev = dev, .action = action, @@ -1391,6 +1444,21 @@ void cx23885_card_setup(struct cx23885_dev *dev) netup_initialize(dev); + netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo); + if (netup_card_rev) + cinfo.rev = netup_card_rev; + + switch (cinfo.rev) { + case 0x4: + filename = "dvb-netup-altera-04.fw"; + break; + default: + filename = "dvb-netup-altera-01.fw"; + break; + } + printk(KERN_INFO "NetUP card rev=0x%x fw_filename=%s\n", + cinfo.rev, filename); + ret = request_firmware(&fw, filename, &dev->pci->dev); if (ret != 0) printk(KERN_ERR "did not find the firmware file. (%s) " diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 419777a832ee2fd929bf0e087add45ad7d09e973..ee41a8882f58470db0f77057c318ca055bcb3802 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -42,6 +42,7 @@ MODULE_DESCRIPTION("Driver for cx23885 based TV cards"); MODULE_AUTHOR("Steven Toth "); MODULE_LICENSE("GPL"); +MODULE_VERSION(CX23885_VERSION); static unsigned int debug; module_param(debug, int, 0644); @@ -2147,14 +2148,8 @@ static struct pci_driver cx23885_pci_driver = { static int __init cx23885_init(void) { - printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n", - (CX23885_VERSION_CODE >> 16) & 0xff, - (CX23885_VERSION_CODE >> 8) & 0xff, - CX23885_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx23885: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif + printk(KERN_INFO "cx23885 driver version %s loaded\n", + CX23885_VERSION); return pci_register_driver(&cx23885_pci_driver); } @@ -2165,5 +2160,3 @@ static void __exit cx23885_fini(void) module_init(cx23885_init); module_exit(cx23885_fini); - -/* ----------------------------------------------------------- */ diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 3c315f94cc8512c33f6a43a264722411fcf43a93..aa83f07b1b0f7bac44c7b72f1893c9346fabecb0 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -37,6 +37,7 @@ #include "tda8290.h" #include "tda18271.h" #include "lgdt330x.h" +#include "xc4000.h" #include "xc5000.h" #include "max2165.h" #include "tda10048.h" @@ -921,6 +922,26 @@ static int dvb_register(struct cx23885_tsport *port) fe->ops.tuner_ops.set_config(fe, &ctl); } break; + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: + i2c_bus = &dev->i2c_bus[0]; + + fe0->dvb.frontend = dvb_attach(zl10353_attach, + &dvico_fusionhdtv_xc3028, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + struct dvb_frontend *fe; + struct xc4000_config cfg = { + .i2c_address = 0x61, + .default_pm = 0, + .dvb_amplitude = 134, + .set_smoothedcvbs = 1, + .if_khz = 4560 + }; + + fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, + &dev->i2c_bus[1].i2c_adap, &cfg); + } + break; case CX23885_BOARD_TBS_6920: i2c_bus = &dev->i2c_bus[1]; @@ -1249,7 +1270,7 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) * implement MFE support. */ fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); - if (fe0->dvb.frontend) + if (fe0 && fe0->dvb.frontend) videobuf_dvb_unregister_bus(&port->frontends); switch (port->dev->board) { diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c index e97cafd839846ed89d63e5ea0391af97ae990320..ce765e3f77bdf6b679ba1b56900035f4f38d51c2 100644 --- a/drivers/media/video/cx23885/cx23885-input.c +++ b/drivers/media/video/cx23885/cx23885-input.c @@ -82,6 +82,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) return; switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_TEVII_S470: @@ -133,6 +134,7 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev) v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_HAUPPAUGE_HVR1250: @@ -229,6 +231,9 @@ static void cx23885_input_ir_stop(struct cx23885_dev *dev) v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); } + flush_work_sync(&dev->cx25840_work); + flush_work_sync(&dev->ir_rx_work); + flush_work_sync(&dev->ir_tx_work); } static void cx23885_input_ir_close(struct rc_dev *rc) @@ -257,6 +262,7 @@ int cx23885_input_init(struct cx23885_dev *dev) return -ENODEV; switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_HAUPPAUGE_HVR1250: diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index ee57f6bedbe3dd186d4f3255d55a0e82d8f4d151..896bb32dbf0301c53863dfae3ae7ae4d8a123fc1 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -1000,7 +1000,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, cx23885_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->version = CX23885_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index c186473fc5706207c3abd529e994b549b44ced0b..d86bc0b1317baca5fdd32b23fb6a1401396c1000 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -36,10 +36,9 @@ #include "cx23885-reg.h" #include "media/cx2341x.h" -#include #include -#define CX23885_VERSION_CODE KERNEL_VERSION(0, 0, 2) +#define CX23885_VERSION "0.0.3" #define UNSET (-1U) @@ -86,6 +85,7 @@ #define CX23885_BOARD_LEADTEK_WINFAST_PXTV1200 28 #define CX23885_BOARD_GOTVIEW_X5_3D_HYBRID 29 #define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30 +#define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000 31 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 423c1af8a782473d21d6bb6eccfe97d3be9effb0..68d1240f493c98f9327858dd9170d75ee232c802 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -113,6 +113,8 @@ MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards"); MODULE_AUTHOR("Ricardo Cerqueira"); MODULE_AUTHOR("Mauro Carvalho Chehab "); MODULE_LICENSE("GPL"); +MODULE_VERSION(CX88_VERSION); + MODULE_SUPPORTED_DEVICE("{{Conexant,23881}," "{{Conexant,23882}," "{{Conexant,23883}"); @@ -973,14 +975,8 @@ static struct pci_driver cx88_audio_pci_driver = { */ static int __init cx88_audio_init(void) { - printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif + printk(KERN_INFO "cx2388x alsa driver version %s loaded\n", + CX88_VERSION); return pci_register_driver(&cx88_audio_pci_driver); } @@ -994,10 +990,3 @@ static void __exit cx88_audio_fini(void) module_init(cx88_audio_init); module_exit(cx88_audio_fini); - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 11e49bbc4a668e4b03e780ddf18649760927d58c..e46446a449c090c91dc43e4eeb1e34e2baf2c16f 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -42,6 +42,7 @@ MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards"); MODULE_AUTHOR("Jelle Foks , Gerd Knorr [SuSE Labs]"); MODULE_LICENSE("GPL"); +MODULE_VERSION(CX88_VERSION); static unsigned int mpegbufs = 32; module_param(mpegbufs,int,0644); @@ -730,7 +731,6 @@ static int vidioc_querycap (struct file *file, void *priv, strcpy(cap->driver, "cx88_blackbird"); strlcpy(cap->card, core->board.name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); - cap->version = CX88_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | @@ -1368,14 +1368,8 @@ static struct cx8802_driver cx8802_blackbird_driver = { static int __init blackbird_init(void) { - printk(KERN_INFO "cx2388x blackbird driver version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif + printk(KERN_INFO "cx2388x blackbird driver version %s loaded\n", + CX88_VERSION); return cx8802_register_driver(&cx8802_blackbird_driver); } @@ -1389,11 +1383,3 @@ module_exit(blackbird_fini); module_param_named(video_debug,cx8802_mpeg_template.debug, int, 0644); MODULE_PARM_DESC(debug,"enable debug messages [video]"); - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 27222c92b603cf140419f7ba1448a62e2cfa3c11..0d719faafd8aeb32e0a260d080622355d8fafa68 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -28,6 +28,7 @@ #include "cx88.h" #include "tea5767.h" +#include "xc4000.h" static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; @@ -2119,6 +2120,99 @@ static const struct cx88_board cx88_boards[] = { }, .mpeg = CX88_MPEG_DVB, }, + [CX88_BOARD_WINFAST_DTV1800H_XC4000] = { + .name = "Leadtek WinFast DTV1800 H (XC4000)", + .tuner_type = TUNER_XC4000, + .radio_type = TUNER_XC4000, + .tuner_addr = 0x61, + .radio_addr = 0x61, + /* + * GPIO setting + * + * 2: mute (0=off,1=on) + * 12: tuner reset pin + * 13: audio source (0=tuner audio,1=line in) + * 14: FM (0=on,1=off ???) + */ + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6040, /* pin 13 = 0, pin 14 = 1 */ + .gpio2 = 0x0000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */ + .gpio2 = 0x0000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */ + .gpio2 = 0x0000, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6000, /* pin 13 = 0, pin 14 = 0 */ + .gpio2 = 0x0000, + }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_WINFAST_DTV2000H_PLUS] = { + .name = "Leadtek WinFast DTV2000 H PLUS", + .tuner_type = TUNER_XC4000, + .radio_type = TUNER_XC4000, + .tuner_addr = 0x61, + .radio_addr = 0x61, + /* + * GPIO + * 2: 1: mute audio + * 12: 0: reset XC4000 + * 13: 1: audio input is line in (0: tuner) + * 14: 0: FM radio + * 16: 0: RF input is cable + */ + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0403, + .gpio1 = 0xF0D7, + .gpio2 = 0x0101, + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_CABLE, + .vmux = 0, + .gpio0 = 0x0403, + .gpio1 = 0xF0D7, + .gpio2 = 0x0100, + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0403, /* was 0x0407 */ + .gpio1 = 0xF0F7, + .gpio2 = 0x0101, + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0403, /* was 0x0407 */ + .gpio1 = 0xF0F7, + .gpio2 = 0x0101, + .gpio3 = 0x0000, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0403, + .gpio1 = 0xF097, + .gpio2 = 0x0100, + .gpio3 = 0x0000, + }, + .mpeg = CX88_MPEG_DVB, + }, [CX88_BOARD_PROF_7301] = { .name = "Prof 7301 DVB-S/S2", .tuner_type = UNSET, @@ -2580,6 +2674,15 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0x107d, .subdevice = 0x6654, .card = CX88_BOARD_WINFAST_DTV1800H, + }, { + /* WinFast DTV1800 H with XC4000 tuner */ + .subvendor = 0x107d, + .subdevice = 0x6f38, + .card = CX88_BOARD_WINFAST_DTV1800H_XC4000, + }, { + .subvendor = 0x107d, + .subdevice = 0x6f42, + .card = CX88_BOARD_WINFAST_DTV2000H_PLUS, }, { /* PVR2000 PAL Model [107d:6630] */ .subvendor = 0x107d, @@ -2846,6 +2949,23 @@ static int cx88_xc3028_winfast1800h_callback(struct cx88_core *core, return -EINVAL; } +static int cx88_xc4000_winfast2000h_plus_callback(struct cx88_core *core, + int command, int arg) +{ + switch (command) { + case XC4000_TUNER_RESET: + /* GPIO 12 (xc4000 tuner reset) */ + cx_set(MO_GP1_IO, 0x1010); + mdelay(50); + cx_clear(MO_GP1_IO, 0x10); + mdelay(75); + cx_set(MO_GP1_IO, 0x10); + mdelay(75); + return 0; + } + return -EINVAL; +} + /* ------------------------------------------------------------------- */ /* some Divco specific stuff */ static int cx88_pv_8000gt_callback(struct cx88_core *core, @@ -2948,6 +3068,19 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core, return -EINVAL; } +static int cx88_xc4000_tuner_callback(struct cx88_core *core, + int command, int arg) +{ + /* Board-specific callbacks */ + switch (core->boardnr) { + case CX88_BOARD_WINFAST_DTV1800H_XC4000: + case CX88_BOARD_WINFAST_DTV2000H_PLUS: + return cx88_xc4000_winfast2000h_plus_callback(core, + command, arg); + } + return -EINVAL; +} + /* ----------------------------------------------------------------------- */ /* Tuner callback function. Currently only needed for the Pinnacle * * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both * @@ -3022,6 +3155,9 @@ int cx88_tuner_callback(void *priv, int component, int command, int arg) case TUNER_XC2028: info_printk(core, "Calling XC2028/3028 callback\n"); return cx88_xc2028_tuner_callback(core, command, arg); + case TUNER_XC4000: + info_printk(core, "Calling XC4000 callback\n"); + return cx88_xc4000_tuner_callback(core, command, arg); case TUNER_XC5000: info_printk(core, "Calling XC5000 callback\n"); return cx88_xc5000_tuner_callback(core, command, arg); @@ -3109,13 +3245,13 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core) case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: case CX88_BOARD_WINFAST_DTV1800H: - /* GPIO 12 (xc3028 tuner reset) */ - cx_set(MO_GP1_IO, 0x1010); - mdelay(50); - cx_clear(MO_GP1_IO, 0x10); - mdelay(50); - cx_set(MO_GP1_IO, 0x10); - mdelay(50); + cx88_xc3028_winfast1800h_callback(core, XC2028_TUNER_RESET, 0); + break; + + case CX88_BOARD_WINFAST_DTV1800H_XC4000: + case CX88_BOARD_WINFAST_DTV2000H_PLUS: + cx88_xc4000_winfast2000h_plus_callback(core, + XC4000_TUNER_RESET, 0); break; case CX88_BOARD_TWINHAN_VP1027_DVBS: diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 2e145f0a5fd99d7c3077c1ab47828db497737663..fbcaa1c5b09da7b43b7f54024a56c4ba7297e55f 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -636,6 +636,9 @@ int cx88_reset(struct cx88_core *core) cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int + /* set default notch filter */ + cx_andor(MO_HTOTAL, 0x1800, (HLNotchFilter4xFsc << 11)); + /* Reset on-board parts */ cx_write(MO_SRST_IO, 0); msleep(10); @@ -759,8 +762,8 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig if (nocomb) value |= (3 << 5); // disable comb filter - cx_write(MO_FILTER_EVEN, value); - cx_write(MO_FILTER_ODD, value); + cx_andor(MO_FILTER_EVEN, 0x7ffc7f, value); /* preserve PEAKEN, PSEL */ + cx_andor(MO_FILTER_ODD, 0x7ffc7f, value); dprintk(1,"set_scale: filter 0x%04x\n", value); return 0; @@ -994,10 +997,10 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) // htotal tmp64 = norm_htotal(norm) * (u64)vdec_clock; do_div(tmp64, fsc8); - htotal = (u32)tmp64 | (HLNotchFilter4xFsc << 11); + htotal = (u32)tmp64; dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n", htotal, cx_read(MO_HTOTAL), (u32)tmp64); - cx_write(MO_HTOTAL, htotal); + cx_andor(MO_HTOTAL, 0x07ff, htotal); // vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes // the effective vbi offset ~244 samples, the same as the Bt8x8 diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index c69df7ebb6a7575f0478a34c7b41142aa83c4cc9..cf3d33ab541b8ee190dcd7fbdaefc6130895a002 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -41,6 +41,7 @@ #include "or51132.h" #include "lgdt330x.h" #include "s5h1409.h" +#include "xc4000.h" #include "xc5000.h" #include "nxt200x.h" #include "cx24123.h" @@ -63,6 +64,7 @@ MODULE_DESCRIPTION("driver for cx2388x based DVB cards"); MODULE_AUTHOR("Chris Pascoe "); MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); MODULE_LICENSE("GPL"); +MODULE_VERSION(CX88_VERSION); static unsigned int debug; module_param(debug, int, 0644); @@ -605,6 +607,39 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev) return 0; } +static int attach_xc4000(struct cx8802_dev *dev, struct xc4000_config *cfg) +{ + struct dvb_frontend *fe; + struct videobuf_dvb_frontend *fe0 = NULL; + + /* Get the first frontend */ + fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); + if (!fe0) + return -EINVAL; + + if (!fe0->dvb.frontend) { + printk(KERN_ERR "%s/2: dvb frontend not attached. " + "Can't attach xc4000\n", + dev->core->name); + return -EINVAL; + } + + fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, &dev->core->i2c_adap, + cfg); + if (!fe) { + printk(KERN_ERR "%s/2: xc4000 attach failed\n", + dev->core->name); + dvb_frontend_detach(fe0->dvb.frontend); + dvb_unregister_frontend(fe0->dvb.frontend); + fe0->dvb.frontend = NULL; + return -EINVAL; + } + + printk(KERN_INFO "%s/2: xc4000 attached\n", dev->core->name); + + return 0; +} + static int cx24116_set_ts_param(struct dvb_frontend *fe, int is_punctured) { @@ -1294,7 +1329,25 @@ static int dvb_register(struct cx8802_dev *dev) goto frontend_detach; } break; - case CX88_BOARD_GENIATECH_X8000_MT: + case CX88_BOARD_WINFAST_DTV1800H_XC4000: + case CX88_BOARD_WINFAST_DTV2000H_PLUS: + fe0->dvb.frontend = dvb_attach(zl10353_attach, + &cx88_pinnacle_hybrid_pctv, + &core->i2c_adap); + if (fe0->dvb.frontend) { + struct xc4000_config cfg = { + .i2c_address = 0x61, + .default_pm = 0, + .dvb_amplitude = 134, + .set_smoothedcvbs = 1, + .if_khz = 4560 + }; + fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; + if (attach_xc4000(dev, &cfg) < 0) + goto frontend_detach; + } + break; + case CX88_BOARD_GENIATECH_X8000_MT: dev->ts_gen_cntrl = 0x00; fe0->dvb.frontend = dvb_attach(zl10353_attach, @@ -1577,6 +1630,11 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv) udelay(1000); break; + case CX88_BOARD_WINFAST_DTV2000H_PLUS: + /* set RF input to AIR for DVB-T (GPIO 16) */ + cx_write(MO_GP2_IO, 0x0101); + break; + default: err = -ENODEV; } @@ -1692,14 +1750,8 @@ static struct cx8802_driver cx8802_dvb_driver = { static int __init dvb_init(void) { - printk(KERN_INFO "cx88/2: cx2388x dvb driver version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif + printk(KERN_INFO "cx88/2: cx2388x dvb driver version %s loaded\n", + CX88_VERSION); return cx8802_register_driver(&cx8802_dvb_driver); } @@ -1710,10 +1762,3 @@ static void __exit dvb_fini(void) module_init(dvb_init); module_exit(dvb_fini); - -/* - * Local variables: - * c-basic-offset: 8 - * compile-command: "make DVB=1" - * End: - */ diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 3f442003623d30494cf63632355bd35e174cc97c..e614201b5ed33b5994ec4528ece3574e7f90919d 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -100,6 +100,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) break; case CX88_BOARD_WINFAST_DTV1000: case CX88_BOARD_WINFAST_DTV1800H: + case CX88_BOARD_WINFAST_DTV1800H_XC4000: + case CX88_BOARD_WINFAST_DTV2000H_PLUS: case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900); auxgpio = gpio; @@ -289,6 +291,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) case CX88_BOARD_WINFAST_DTV2000H: case CX88_BOARD_WINFAST_DTV2000H_J: case CX88_BOARD_WINFAST_DTV1800H: + case CX88_BOARD_WINFAST_DTV1800H_XC4000: + case CX88_BOARD_WINFAST_DTV2000H_PLUS: ir_codes = RC_MAP_WINFAST; ir->gpio_addr = MO_GP0_IO; ir->mask_keycode = 0x8f8; diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 1a7b983f82976eeb5b66a0da1fc6316104faee45..cd5386ee210cf02f79fbfb4abaeb86895e88ab99 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -39,6 +39,7 @@ MODULE_AUTHOR("Jelle Foks "); MODULE_AUTHOR("Chris Pascoe "); MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); MODULE_LICENSE("GPL"); +MODULE_VERSION(CX88_VERSION); static unsigned int debug; module_param(debug,int,0644); @@ -613,13 +614,17 @@ static int cx8802_request_acquire(struct cx8802_driver *drv) core->active_type_id != drv->type_id) return -EBUSY; - core->input = 0; - for (i = 0; - i < (sizeof(core->board.input) / sizeof(struct cx88_input)); - i++) { - if (core->board.input[i].type == CX88_VMUX_DVB) { - core->input = i; - break; + if (drv->type_id == CX88_MPEG_DVB) { + /* When switching to DVB, always set the input to the tuner */ + core->last_analog_input = core->input; + core->input = 0; + for (i = 0; + i < (sizeof(core->board.input) / sizeof(struct cx88_input)); + i++) { + if (core->board.input[i].type == CX88_VMUX_DVB) { + core->input = i; + break; + } } } @@ -644,6 +649,12 @@ static int cx8802_request_release(struct cx8802_driver *drv) if (drv->advise_release && --core->active_ref == 0) { + if (drv->type_id == CX88_MPEG_DVB) { + /* If the DVB driver is releasing, reset the input + state to the last configured analog input */ + core->input = core->last_analog_input; + } + drv->advise_release(drv); core->active_type_id = CX88_BOARD_NONE; mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO)); @@ -890,14 +901,8 @@ static struct pci_driver cx8802_pci_driver = { static int __init cx8802_init(void) { - printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif + printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %s loaded\n", + CX88_VERSION); return pci_register_driver(&cx8802_pci_driver); } diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index cef4f282e5aae97c28eaa5515ad03db206cb8664..60d28fdd77911c286a1d9ec365aa37e976f5cdee 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -45,6 +45,7 @@ MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); MODULE_LICENSE("GPL"); +MODULE_VERSION(CX88_VERSION); /* ------------------------------------------------------------------ */ @@ -220,7 +221,23 @@ static const struct cx88_ctrl cx8800_ctls[] = { .reg = MO_UV_SATURATION, .mask = 0x00ff, .shift = 0, - },{ + }, { + .v = { + .id = V4L2_CID_SHARPNESS, + .name = "Sharpness", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0x0, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 0, + /* NOTE: the value is converted and written to both even + and odd registers in the code */ + .reg = MO_FILTER_ODD, + .mask = 7 << 7, + .shift = 7, + }, { .v = { .id = V4L2_CID_CHROMA_AGC, .name = "Chroma AGC", @@ -244,6 +261,20 @@ static const struct cx88_ctrl cx8800_ctls[] = { .reg = MO_INPUT_FORMAT, .mask = 1 << 9, .shift = 9, + }, { + .v = { + .id = V4L2_CID_BAND_STOP_FILTER, + .name = "Notch filter", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0x0, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 0, + .reg = MO_HTOTAL, + .mask = 3 << 11, + .shift = 11, }, { /* --- audio --- */ .v = { @@ -300,8 +331,10 @@ const u32 cx88_user_ctrls[] = { V4L2_CID_AUDIO_VOLUME, V4L2_CID_AUDIO_BALANCE, V4L2_CID_AUDIO_MUTE, + V4L2_CID_SHARPNESS, V4L2_CID_CHROMA_AGC, V4L2_CID_COLOR_KILLER, + V4L2_CID_BAND_STOP_FILTER, 0 }; EXPORT_SYMBOL(cx88_user_ctrls); @@ -962,6 +995,10 @@ int cx88_get_control (struct cx88_core *core, struct v4l2_control *ctl) case V4L2_CID_AUDIO_VOLUME: ctl->value = 0x3f - (value & 0x3f); break; + case V4L2_CID_SHARPNESS: + ctl->value = ((value & 0x0200) ? (((value & 0x0180) >> 7) + 1) + : 0); + break; default: ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift; break; @@ -1039,6 +1076,12 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl) } mask=0xffff; break; + case V4L2_CID_SHARPNESS: + /* 0b000, 0b100, 0b101, 0b110, or 0b111 */ + value = (ctl->value < 1 ? 0 : ((ctl->value + 3) << 7)); + /* needs to be set for both fields */ + cx_andor(MO_FILTER_EVEN, mask, value); + break; case V4L2_CID_CHROMA_AGC: /* Do not allow chroma AGC to be enabled for SECAM */ value = ((ctl->value - c->off) << c->shift) & c->mask; @@ -1161,7 +1204,6 @@ static int vidioc_querycap (struct file *file, void *priv, strcpy(cap->driver, "cx8800"); strlcpy(cap->card, core->board.name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); - cap->version = CX88_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | @@ -1480,7 +1522,6 @@ static int radio_querycap (struct file *file, void *priv, strcpy(cap->driver, "cx8800"); strlcpy(cap->card, core->board.name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); - cap->version = CX88_VERSION_CODE; cap->capabilities = V4L2_CAP_TUNER; return 0; } @@ -2139,14 +2180,8 @@ static struct pci_driver cx8800_pci_driver = { static int __init cx8800_init(void) { - printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif + printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %s loaded\n", + CX88_VERSION); return pci_register_driver(&cx8800_pci_driver); } @@ -2157,11 +2192,3 @@ static void __exit cx8800_fini(void) module_init(cx8800_init); module_exit(cx8800_fini); - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index a399a8b086babf4e9facf27a690cdb577a5b6427..fa8d307e1a3d2299618bdf5266aea118b68f7670 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -39,9 +39,9 @@ #include "cx88-reg.h" #include "tuner-xc2028.h" -#include #include -#define CX88_VERSION_CODE KERNEL_VERSION(0, 0, 8) + +#define CX88_VERSION "0.0.9" #define UNSET (-1U) @@ -242,6 +242,8 @@ extern const struct sram_channel const cx88_sram_channels[]; #define CX88_BOARD_SAMSUNG_SMT_7020 84 #define CX88_BOARD_TWINHAN_VP1027_DVBS 85 #define CX88_BOARD_TEVII_S464 86 +#define CX88_BOARD_WINFAST_DTV2000H_PLUS 87 +#define CX88_BOARD_WINFAST_DTV1800H_XC4000 88 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, @@ -375,6 +377,7 @@ struct cx88_core { u32 audiomode_manual; u32 audiomode_current; u32 input; + u32 last_analog_input; u32 astat; u32 use_nicam; unsigned long last_change; diff --git a/drivers/media/video/davinci/Kconfig b/drivers/media/video/davinci/Kconfig index 6b1954035649c9589c4e246e8be6d453f8be67d9..60a456ebdc7cd7b2972643a43695e89388c2f0ee 100644 --- a/drivers/media/video/davinci/Kconfig +++ b/drivers/media/video/davinci/Kconfig @@ -91,3 +91,26 @@ config VIDEO_ISIF To compile this driver as a module, choose M here: the module will be called vpfe. + +config VIDEO_DM644X_VPBE + tristate "DM644X VPBE HW module" + depends on ARCH_DAVINCI_DM644x + select VIDEO_VPSS_SYSTEM + select VIDEOBUF_DMA_CONTIG + help + Enables VPBE modules used for display on a DM644x + SoC. + + To compile this driver as a module, choose M here: the + module will be called vpbe. + + +config VIDEO_VPBE_DISPLAY + tristate "VPBE V4L2 Display driver" + depends on ARCH_DAVINCI_DM644x + select VIDEO_DM644X_VPBE + help + Enables VPBE V4L2 Display driver on a DM644x device + + To compile this driver as a module, choose M here: the + module will be called vpbe_display. diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile index a37955745aaa45fbe7778c67e729f53f49316b7f..ae7dafb689ab9917678f16a81fb00072f337bff4 100644 --- a/drivers/media/video/davinci/Makefile +++ b/drivers/media/video/davinci/Makefile @@ -16,3 +16,5 @@ obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o obj-$(CONFIG_VIDEO_ISIF) += isif.o +obj-$(CONFIG_VIDEO_DM644X_VPBE) += vpbe.o vpbe_osd.o vpbe_venc.o +obj-$(CONFIG_VIDEO_VPBE_DISPLAY) += vpbe_display.o diff --git a/drivers/media/video/davinci/vpbe.c b/drivers/media/video/davinci/vpbe.c new file mode 100644 index 0000000000000000000000000000000000000000..d773d30de221f0bc7d5fd04e6ea660ff9b2f3940 --- /dev/null +++ b/drivers/media/video/davinci/vpbe.c @@ -0,0 +1,864 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 version 2. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define VPBE_DEFAULT_OUTPUT "Composite" +#define VPBE_DEFAULT_MODE "ntsc" + +static char *def_output = VPBE_DEFAULT_OUTPUT; +static char *def_mode = VPBE_DEFAULT_MODE; +static int debug; + +module_param(def_output, charp, S_IRUGO); +module_param(def_mode, charp, S_IRUGO); +module_param(debug, int, 0644); + +MODULE_PARM_DESC(def_output, "vpbe output name (default:Composite)"); +MODULE_PARM_DESC(def_mode, "vpbe output mode name (default:ntsc"); +MODULE_PARM_DESC(debug, "Debug level 0-1"); + +MODULE_DESCRIPTION("TI DMXXX VPBE Display controller"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Texas Instruments"); + +/** + * vpbe_current_encoder_info - Get config info for current encoder + * @vpbe_dev - vpbe device ptr + * + * Return ptr to current encoder config info + */ +static struct encoder_config_info* +vpbe_current_encoder_info(struct vpbe_device *vpbe_dev) +{ + struct vpbe_config *cfg = vpbe_dev->cfg; + int index = vpbe_dev->current_sd_index; + + return ((index == 0) ? &cfg->venc : + &cfg->ext_encoders[index-1]); +} + +/** + * vpbe_find_encoder_sd_index - Given a name find encoder sd index + * + * @vpbe_config - ptr to vpbe cfg + * @output_index - index used by application + * + * Return sd index of the encoder + */ +static int vpbe_find_encoder_sd_index(struct vpbe_config *cfg, + int index) +{ + char *encoder_name = cfg->outputs[index].subdev_name; + int i; + + /* Venc is always first */ + if (!strcmp(encoder_name, cfg->venc.module_name)) + return 0; + + for (i = 0; i < cfg->num_ext_encoders; i++) { + if (!strcmp(encoder_name, + cfg->ext_encoders[i].module_name)) + return i+1; + } + + return -EINVAL; +} + +/** + * vpbe_g_cropcap - Get crop capabilities of the display + * @vpbe_dev - vpbe device ptr + * @cropcap - cropcap is a ptr to struct v4l2_cropcap + * + * Update the crop capabilities in crop cap for current + * mode + */ +static int vpbe_g_cropcap(struct vpbe_device *vpbe_dev, + struct v4l2_cropcap *cropcap) +{ + if (NULL == cropcap) + return -EINVAL; + cropcap->bounds.left = 0; + cropcap->bounds.top = 0; + cropcap->bounds.width = vpbe_dev->current_timings.xres; + cropcap->bounds.height = vpbe_dev->current_timings.yres; + cropcap->defrect = cropcap->bounds; + + return 0; +} + +/** + * vpbe_enum_outputs - enumerate outputs + * @vpbe_dev - vpbe device ptr + * @output - ptr to v4l2_output structure + * + * Enumerates the outputs available at the vpbe display + * returns the status, -EINVAL if end of output list + */ +static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev, + struct v4l2_output *output) +{ + struct vpbe_config *cfg = vpbe_dev->cfg; + int temp_index = output->index; + + if (temp_index >= cfg->num_outputs) + return -EINVAL; + + *output = cfg->outputs[temp_index].output; + output->index = temp_index; + + return 0; +} + +static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode) +{ + struct vpbe_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index; + int i; + + if (NULL == mode) + return -EINVAL; + + for (i = 0; i < cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if (!strcmp(mode, var.name)) { + vpbe_dev->current_timings = var; + return 0; + } + } + + return -EINVAL; +} + +static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info *mode_info) +{ + if (NULL == mode_info) + return -EINVAL; + + *mode_info = vpbe_dev->current_timings; + + return 0; +} + +static int vpbe_get_dv_preset_info(struct vpbe_device *vpbe_dev, + unsigned int dv_preset) +{ + struct vpbe_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index; + int i; + + for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if ((var.timings_type & VPBE_ENC_DV_PRESET) && + (var.timings.dv_preset == dv_preset)) { + vpbe_dev->current_timings = var; + return 0; + } + } + + return -EINVAL; +} + +/* Get std by std id */ +static int vpbe_get_std_info(struct vpbe_device *vpbe_dev, + v4l2_std_id std_id) +{ + struct vpbe_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index; + int i; + + for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if ((var.timings_type & VPBE_ENC_STD) && + (var.timings.std_id & std_id)) { + vpbe_dev->current_timings = var; + return 0; + } + } + + return -EINVAL; +} + +static int vpbe_get_std_info_by_name(struct vpbe_device *vpbe_dev, + char *std_name) +{ + struct vpbe_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index; + int i; + + for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if (!strcmp(var.name, std_name)) { + vpbe_dev->current_timings = var; + return 0; + } + } + + return -EINVAL; +} + +/** + * vpbe_set_output - Set output + * @vpbe_dev - vpbe device ptr + * @index - index of output + * + * Set vpbe output to the output specified by the index + */ +static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) +{ + struct encoder_config_info *curr_enc_info = + vpbe_current_encoder_info(vpbe_dev); + struct vpbe_config *cfg = vpbe_dev->cfg; + int enc_out_index; + int sd_index; + int ret = 0; + + if (index >= cfg->num_outputs) + return -EINVAL; + + mutex_lock(&vpbe_dev->lock); + + sd_index = vpbe_dev->current_sd_index; + enc_out_index = cfg->outputs[index].output.index; + /* + * Currently we switch the encoder based on output selected + * by the application. If media controller is implemented later + * there is will be an API added to setup_link between venc + * and external encoder. So in that case below comparison always + * match and encoder will not be switched. But if application + * chose not to use media controller, then this provides current + * way of switching encoder at the venc output. + */ + if (strcmp(curr_enc_info->module_name, + cfg->outputs[index].subdev_name)) { + /* Need to switch the encoder at the output */ + sd_index = vpbe_find_encoder_sd_index(cfg, index); + if (sd_index < 0) { + ret = -EINVAL; + goto out; + } + + if (ret) + goto out; + } + + /* Set output at the encoder */ + ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, + s_routing, 0, enc_out_index, 0); + if (ret) + goto out; + + /* + * It is assumed that venc or extenal encoder will set a default + * mode in the sub device. For external encoder or LCD pannel output, + * we also need to set up the lcd port for the required mode. So setup + * the lcd port for the default mode that is configured in the board + * arch/arm/mach-davinci/board-dm355-evm.setup file for the external + * encoder. + */ + ret = vpbe_get_mode_info(vpbe_dev, + cfg->outputs[index].default_mode); + if (!ret) { + struct osd_state *osd_device = vpbe_dev->osd_device; + + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + vpbe_dev->current_sd_index = sd_index; + vpbe_dev->current_out_index = index; + } +out: + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +static int vpbe_set_default_output(struct vpbe_device *vpbe_dev) +{ + struct vpbe_config *cfg = vpbe_dev->cfg; + int ret = 0; + int i; + + for (i = 0; i < cfg->num_outputs; i++) { + if (!strcmp(def_output, + cfg->outputs[i].output.name)) { + ret = vpbe_set_output(vpbe_dev, i); + if (!ret) + vpbe_dev->current_out_index = i; + return ret; + } + } + return ret; +} + +/** + * vpbe_get_output - Get output + * @vpbe_dev - vpbe device ptr + * + * return current vpbe output to the the index + */ +static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev) +{ + return vpbe_dev->current_out_index; +} + +/** + * vpbe_s_dv_preset - Set the given preset timings in the encoder + * + * Sets the preset if supported by the current encoder. Return the status. + * 0 - success & -EINVAL on error + */ +static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset) +{ + struct vpbe_config *cfg = vpbe_dev->cfg; + int out_index = vpbe_dev->current_out_index; + int sd_index = vpbe_dev->current_sd_index; + int ret; + + + if (!(cfg->outputs[out_index].output.capabilities & + V4L2_OUT_CAP_PRESETS)) + return -EINVAL; + + ret = vpbe_get_dv_preset_info(vpbe_dev, dv_preset->preset); + + if (ret) + return ret; + + mutex_lock(&vpbe_dev->lock); + + + ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, + s_dv_preset, dv_preset); + /* set the lcd controller output for the given mode */ + if (!ret) { + struct osd_state *osd_device = vpbe_dev->osd_device; + + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + } + mutex_unlock(&vpbe_dev->lock); + + return ret; +} + +/** + * vpbe_g_dv_preset - Get the preset in the current encoder + * + * Get the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_g_dv_preset(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset) +{ + if (vpbe_dev->current_timings.timings_type & + VPBE_ENC_DV_PRESET) { + dv_preset->preset = vpbe_dev->current_timings.timings.dv_preset; + return 0; + } + + return -EINVAL; +} + +/** + * vpbe_enum_dv_presets - Enumerate the dv presets in the current encoder + * + * Get the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev, + struct v4l2_dv_enum_preset *preset_info) +{ + struct vpbe_config *cfg = vpbe_dev->cfg; + int out_index = vpbe_dev->current_out_index; + struct vpbe_output *output = &cfg->outputs[out_index]; + int j = 0; + int i; + + if (!(output->output.capabilities & V4L2_OUT_CAP_PRESETS)) + return -EINVAL; + + for (i = 0; i < output->num_modes; i++) { + if (output->modes[i].timings_type == VPBE_ENC_DV_PRESET) { + if (j == preset_info->index) + break; + j++; + } + } + + if (i == output->num_modes) + return -EINVAL; + + return v4l_fill_dv_preset_info(output->modes[i].timings.dv_preset, + preset_info); +} + +/** + * vpbe_s_std - Set the given standard in the encoder + * + * Sets the standard if supported by the current encoder. Return the status. + * 0 - success & -EINVAL on error + */ +static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) +{ + struct vpbe_config *cfg = vpbe_dev->cfg; + int out_index = vpbe_dev->current_out_index; + int sd_index = vpbe_dev->current_sd_index; + int ret; + + if (!(cfg->outputs[out_index].output.capabilities & + V4L2_OUT_CAP_STD)) + return -EINVAL; + + ret = vpbe_get_std_info(vpbe_dev, *std_id); + if (ret) + return ret; + + mutex_lock(&vpbe_dev->lock); + + ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, + s_std_output, *std_id); + /* set the lcd controller output for the given mode */ + if (!ret) { + struct osd_state *osd_device = vpbe_dev->osd_device; + + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + } + mutex_unlock(&vpbe_dev->lock); + + return ret; +} + +/** + * vpbe_g_std - Get the standard in the current encoder + * + * Get the standard in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) +{ + struct vpbe_enc_mode_info cur_timings = vpbe_dev->current_timings; + + if (cur_timings.timings_type & VPBE_ENC_STD) { + *std_id = cur_timings.timings.std_id; + return 0; + } + + return -EINVAL; +} + +/** + * vpbe_set_mode - Set mode in the current encoder using mode info + * + * Use the mode string to decide what timings to set in the encoder + * This is typically useful when fbset command is used to change the current + * timings by specifying a string to indicate the timings. + */ +static int vpbe_set_mode(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info *mode_info) +{ + struct vpbe_enc_mode_info *preset_mode = NULL; + struct vpbe_config *cfg = vpbe_dev->cfg; + struct v4l2_dv_preset dv_preset; + struct osd_state *osd_device; + int out_index = vpbe_dev->current_out_index; + int ret = 0; + int i; + + if ((NULL == mode_info) || (NULL == mode_info->name)) + return -EINVAL; + + for (i = 0; i < cfg->outputs[out_index].num_modes; i++) { + if (!strcmp(mode_info->name, + cfg->outputs[out_index].modes[i].name)) { + preset_mode = &cfg->outputs[out_index].modes[i]; + /* + * it may be one of the 3 timings type. Check and + * invoke right API + */ + if (preset_mode->timings_type & VPBE_ENC_STD) + return vpbe_s_std(vpbe_dev, + &preset_mode->timings.std_id); + if (preset_mode->timings_type & VPBE_ENC_DV_PRESET) { + dv_preset.preset = + preset_mode->timings.dv_preset; + return vpbe_s_dv_preset(vpbe_dev, &dv_preset); + } + } + } + + /* Only custom timing should reach here */ + if (preset_mode == NULL) + return -EINVAL; + + mutex_lock(&vpbe_dev->lock); + + osd_device = vpbe_dev->osd_device; + vpbe_dev->current_timings = *preset_mode; + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + + mutex_unlock(&vpbe_dev->lock); + + return ret; +} + +static int vpbe_set_default_mode(struct vpbe_device *vpbe_dev) +{ + int ret; + + ret = vpbe_get_std_info_by_name(vpbe_dev, def_mode); + if (ret) + return ret; + + /* set the default mode in the encoder */ + return vpbe_set_mode(vpbe_dev, &vpbe_dev->current_timings); +} + +static int platform_device_get(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct vpbe_device *vpbe_dev = data; + + if (strcmp("vpbe-osd", pdev->name) == 0) + vpbe_dev->osd_device = platform_get_drvdata(pdev); + + return 0; +} + +/** + * vpbe_initialize() - Initialize the vpbe display controller + * @vpbe_dev - vpbe device ptr + * + * Master frame buffer device drivers calls this to initialize vpbe + * display controller. This will then registers v4l2 device and the sub + * devices and sets a current encoder sub device for display. v4l2 display + * device driver is the master and frame buffer display device driver is + * the slave. Frame buffer display driver checks the initialized during + * probe and exit if not initialized. Returns status. + */ +static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) +{ + struct encoder_config_info *enc_info; + struct v4l2_subdev **enc_subdev; + struct osd_state *osd_device; + struct i2c_adapter *i2c_adap; + int output_index; + int num_encoders; + int ret = 0; + int err; + int i; + + /* + * v4l2 abd FBDev frame buffer devices will get the vpbe_dev pointer + * from the platform device by iteration of platform drivers and + * matching with device name + */ + if (NULL == vpbe_dev || NULL == dev) { + printk(KERN_ERR "Null device pointers.\n"); + return -ENODEV; + } + + if (vpbe_dev->initialized) + return 0; + + mutex_lock(&vpbe_dev->lock); + + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) { + /* We have dac clock available for platform */ + vpbe_dev->dac_clk = clk_get(vpbe_dev->pdev, "vpss_dac"); + if (IS_ERR(vpbe_dev->dac_clk)) { + ret = PTR_ERR(vpbe_dev->dac_clk); + goto vpbe_unlock; + } + if (clk_enable(vpbe_dev->dac_clk)) { + ret = -ENODEV; + goto vpbe_unlock; + } + } + + /* first enable vpss clocks */ + vpss_enable_clock(VPSS_VPBE_CLOCK, 1); + + /* First register a v4l2 device */ + ret = v4l2_device_register(dev, &vpbe_dev->v4l2_dev); + if (ret) { + v4l2_err(dev->driver, + "Unable to register v4l2 device.\n"); + goto vpbe_fail_clock; + } + v4l2_info(&vpbe_dev->v4l2_dev, "vpbe v4l2 device registered\n"); + + err = bus_for_each_dev(&platform_bus_type, NULL, vpbe_dev, + platform_device_get); + if (err < 0) + return err; + + vpbe_dev->venc = venc_sub_dev_init(&vpbe_dev->v4l2_dev, + vpbe_dev->cfg->venc.module_name); + /* register venc sub device */ + if (vpbe_dev->venc == NULL) { + v4l2_err(&vpbe_dev->v4l2_dev, + "vpbe unable to init venc sub device\n"); + ret = -ENODEV; + goto vpbe_fail_v4l2_device; + } + /* initialize osd device */ + osd_device = vpbe_dev->osd_device; + + if (NULL != osd_device->ops.initialize) { + err = osd_device->ops.initialize(osd_device); + if (err) { + v4l2_err(&vpbe_dev->v4l2_dev, + "unable to initialize the OSD device"); + err = -ENOMEM; + goto vpbe_fail_v4l2_device; + } + } + + /* + * Register any external encoders that are configured. At index 0 we + * store venc sd index. + */ + num_encoders = vpbe_dev->cfg->num_ext_encoders + 1; + vpbe_dev->encoders = kmalloc( + sizeof(struct v4l2_subdev *)*num_encoders, + GFP_KERNEL); + if (NULL == vpbe_dev->encoders) { + v4l2_err(&vpbe_dev->v4l2_dev, + "unable to allocate memory for encoders sub devices"); + ret = -ENOMEM; + goto vpbe_fail_v4l2_device; + } + + i2c_adap = i2c_get_adapter(vpbe_dev->cfg->i2c_adapter_id); + for (i = 0; i < (vpbe_dev->cfg->num_ext_encoders + 1); i++) { + if (i == 0) { + /* venc is at index 0 */ + enc_subdev = &vpbe_dev->encoders[i]; + *enc_subdev = vpbe_dev->venc; + continue; + } + enc_info = &vpbe_dev->cfg->ext_encoders[i]; + if (enc_info->is_i2c) { + enc_subdev = &vpbe_dev->encoders[i]; + *enc_subdev = v4l2_i2c_new_subdev_board( + &vpbe_dev->v4l2_dev, i2c_adap, + &enc_info->board_info, NULL); + if (*enc_subdev) + v4l2_info(&vpbe_dev->v4l2_dev, + "v4l2 sub device %s registered\n", + enc_info->module_name); + else { + v4l2_err(&vpbe_dev->v4l2_dev, "encoder %s" + " failed to register", + enc_info->module_name); + ret = -ENODEV; + goto vpbe_fail_sd_register; + } + } else + v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders" + " currently not supported"); + } + + /* set the current encoder and output to that of venc by default */ + vpbe_dev->current_sd_index = 0; + vpbe_dev->current_out_index = 0; + output_index = 0; + + mutex_unlock(&vpbe_dev->lock); + + printk(KERN_NOTICE "Setting default output to %s\n", def_output); + ret = vpbe_set_default_output(vpbe_dev); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s", + def_output); + return ret; + } + + printk(KERN_NOTICE "Setting default mode to %s\n", def_mode); + ret = vpbe_set_default_mode(vpbe_dev); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s", + def_mode); + return ret; + } + vpbe_dev->initialized = 1; + /* TBD handling of bootargs for default output and mode */ + return 0; + +vpbe_fail_sd_register: + kfree(vpbe_dev->encoders); +vpbe_fail_v4l2_device: + v4l2_device_unregister(&vpbe_dev->v4l2_dev); +vpbe_fail_clock: + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) + clk_put(vpbe_dev->dac_clk); +vpbe_unlock: + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +/** + * vpbe_deinitialize() - de-initialize the vpbe display controller + * @dev - Master and slave device ptr + * + * vpbe_master and slave frame buffer devices calls this to de-initialize + * the display controller. It is called when master and slave device + * driver modules are removed and no longer requires the display controller. + */ +static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev) +{ + v4l2_device_unregister(&vpbe_dev->v4l2_dev); + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) + clk_put(vpbe_dev->dac_clk); + + kfree(vpbe_dev->encoders); + vpbe_dev->initialized = 0; + /* disable vpss clocks */ + vpss_enable_clock(VPSS_VPBE_CLOCK, 0); +} + +static struct vpbe_device_ops vpbe_dev_ops = { + .g_cropcap = vpbe_g_cropcap, + .enum_outputs = vpbe_enum_outputs, + .set_output = vpbe_set_output, + .get_output = vpbe_get_output, + .s_dv_preset = vpbe_s_dv_preset, + .g_dv_preset = vpbe_g_dv_preset, + .enum_dv_presets = vpbe_enum_dv_presets, + .s_std = vpbe_s_std, + .g_std = vpbe_g_std, + .initialize = vpbe_initialize, + .deinitialize = vpbe_deinitialize, + .get_mode_info = vpbe_get_current_mode_info, + .set_mode = vpbe_set_mode, +}; + +static __devinit int vpbe_probe(struct platform_device *pdev) +{ + struct vpbe_device *vpbe_dev; + struct vpbe_config *cfg; + int ret = -EINVAL; + + if (pdev->dev.platform_data == NULL) { + v4l2_err(pdev->dev.driver, "No platform data\n"); + return -ENODEV; + } + cfg = pdev->dev.platform_data; + + if (!cfg->module_name[0] || + !cfg->osd.module_name[0] || + !cfg->venc.module_name[0]) { + v4l2_err(pdev->dev.driver, "vpbe display module names not" + " defined\n"); + return ret; + } + + vpbe_dev = kzalloc(sizeof(*vpbe_dev), GFP_KERNEL); + if (vpbe_dev == NULL) { + v4l2_err(pdev->dev.driver, "Unable to allocate memory" + " for vpbe_device\n"); + return -ENOMEM; + } + vpbe_dev->cfg = cfg; + vpbe_dev->ops = vpbe_dev_ops; + vpbe_dev->pdev = &pdev->dev; + + if (cfg->outputs->num_modes > 0) + vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0]; + else + return -ENODEV; + + /* set the driver data in platform device */ + platform_set_drvdata(pdev, vpbe_dev); + mutex_init(&vpbe_dev->lock); + + return 0; +} + +static int vpbe_remove(struct platform_device *device) +{ + struct vpbe_device *vpbe_dev = platform_get_drvdata(device); + + kfree(vpbe_dev); + + return 0; +} + +static struct platform_driver vpbe_driver = { + .driver = { + .name = "vpbe_controller", + .owner = THIS_MODULE, + }, + .probe = vpbe_probe, + .remove = vpbe_remove, +}; + +/** + * vpbe_init: initialize the vpbe driver + * + * This function registers device and driver to the kernel + */ +static __init int vpbe_init(void) +{ + return platform_driver_register(&vpbe_driver); +} + +/** + * vpbe_cleanup : cleanup function for vpbe driver + * + * This will un-registers the device and driver to the kernel + */ +static void vpbe_cleanup(void) +{ + platform_driver_unregister(&vpbe_driver); +} + +/* Function for module initialization and cleanup */ +module_init(vpbe_init); +module_exit(vpbe_cleanup); diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c new file mode 100644 index 0000000000000000000000000000000000000000..7f1d83a6d5759e1ec0132bdfa7bd61bcfa7f222c --- /dev/null +++ b/drivers/media/video/davinci/vpbe_display.c @@ -0,0 +1,1860 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vpbe_venc_regs.h" + +#define VPBE_DISPLAY_DRIVER "vpbe-v4l2" + +static int debug; + +#define VPBE_DISPLAY_SD_BUF_SIZE (720*576*2) +#define VPBE_DEFAULT_NUM_BUFS 3 + +module_param(debug, int, 0644); + +static int venc_is_second_field(struct vpbe_display *disp_dev) +{ + struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; + int ret; + int val; + + ret = v4l2_subdev_call(vpbe_dev->venc, + core, + ioctl, + VENC_GET_FLD, + &val); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in getting Field ID 0\n"); + } + return val; +} + +static void vpbe_isr_even_field(struct vpbe_display *disp_obj, + struct vpbe_layer *layer) +{ + struct timespec timevalue; + + if (layer->cur_frm == layer->next_frm) + return; + ktime_get_ts(&timevalue); + layer->cur_frm->ts.tv_sec = timevalue.tv_sec; + layer->cur_frm->ts.tv_usec = timevalue.tv_nsec / NSEC_PER_USEC; + layer->cur_frm->state = VIDEOBUF_DONE; + wake_up_interruptible(&layer->cur_frm->done); + /* Make cur_frm pointing to next_frm */ + layer->cur_frm = layer->next_frm; +} + +static void vpbe_isr_odd_field(struct vpbe_display *disp_obj, + struct vpbe_layer *layer) +{ + struct osd_state *osd_device = disp_obj->osd_device; + unsigned long addr; + + spin_lock(&disp_obj->dma_queue_lock); + if (list_empty(&layer->dma_queue) || + (layer->cur_frm != layer->next_frm)) { + spin_unlock(&disp_obj->dma_queue_lock); + return; + } + /* + * one field is displayed configure + * the next frame if it is available + * otherwise hold on current frame + * Get next from the buffer queue + */ + layer->next_frm = list_entry( + layer->dma_queue.next, + struct videobuf_buffer, + queue); + /* Remove that from the buffer queue */ + list_del(&layer->next_frm->queue); + spin_unlock(&disp_obj->dma_queue_lock); + /* Mark state of the frame to active */ + layer->next_frm->state = VIDEOBUF_ACTIVE; + addr = videobuf_to_dma_contig(layer->next_frm); + osd_device->ops.start_layer(osd_device, + layer->layer_info.id, + addr, + disp_obj->cbcr_ofst); +} + +/* interrupt service routine */ +static irqreturn_t venc_isr(int irq, void *arg) +{ + struct vpbe_display *disp_dev = (struct vpbe_display *)arg; + struct vpbe_layer *layer; + static unsigned last_event; + unsigned event = 0; + int fid; + int i; + + if ((NULL == arg) || (NULL == disp_dev->dev[0])) + return IRQ_HANDLED; + + if (venc_is_second_field(disp_dev)) + event |= VENC_SECOND_FIELD; + else + event |= VENC_FIRST_FIELD; + + if (event == (last_event & ~VENC_END_OF_FRAME)) { + /* + * If the display is non-interlaced, then we need to flag the + * end-of-frame event at every interrupt regardless of the + * value of the FIDST bit. We can conclude that the display is + * non-interlaced if the value of the FIDST bit is unchanged + * from the previous interrupt. + */ + event |= VENC_END_OF_FRAME; + } else if (event == VENC_SECOND_FIELD) { + /* end-of-frame for interlaced display */ + event |= VENC_END_OF_FRAME; + } + last_event = event; + + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + layer = disp_dev->dev[i]; + /* If streaming is started in this layer */ + if (!layer->started) + continue; + + if (layer->layer_first_int) { + layer->layer_first_int = 0; + continue; + } + /* Check the field format */ + if ((V4L2_FIELD_NONE == layer->pix_fmt.field) && + (event & VENC_END_OF_FRAME)) { + /* Progressive mode */ + + vpbe_isr_even_field(disp_dev, layer); + vpbe_isr_odd_field(disp_dev, layer); + } else { + /* Interlaced mode */ + + layer->field_id ^= 1; + if (event & VENC_FIRST_FIELD) + fid = 0; + else + fid = 1; + + /* + * If field id does not match with store + * field id + */ + if (fid != layer->field_id) { + /* Make them in sync */ + layer->field_id = fid; + continue; + } + /* + * device field id and local field id are + * in sync. If this is even field + */ + if (0 == fid) + vpbe_isr_even_field(disp_dev, layer); + else /* odd field */ + vpbe_isr_odd_field(disp_dev, layer); + } + } + + return IRQ_HANDLED; +} + +/* + * vpbe_buffer_prepare() + * This is the callback function called from videobuf_qbuf() function + * the buffer is prepared and user space virtual address is converted into + * physical address + */ +static int vpbe_buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct vpbe_fh *fh = q->priv_data; + struct vpbe_layer *layer = fh->layer; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + unsigned long addr; + int ret; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe_buffer_prepare\n"); + + /* If buffer is not initialized, initialize it */ + if (VIDEOBUF_NEEDS_INIT == vb->state) { + vb->width = layer->pix_fmt.width; + vb->height = layer->pix_fmt.height; + vb->size = layer->pix_fmt.sizeimage; + vb->field = field; + + ret = videobuf_iolock(q, vb, NULL); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, "Failed to map \ + user address\n"); + return -EINVAL; + } + + addr = videobuf_to_dma_contig(vb); + + if (q->streaming) { + if (!IS_ALIGNED(addr, 8)) { + v4l2_err(&vpbe_dev->v4l2_dev, + "buffer_prepare:offset is \ + not aligned to 32 bytes\n"); + return -EINVAL; + } + } + vb->state = VIDEOBUF_PREPARED; + } + return 0; +} + +/* + * vpbe_buffer_setup() + * This function allocates memory for the buffers + */ +static int vpbe_buffer_setup(struct videobuf_queue *q, + unsigned int *count, + unsigned int *size) +{ + /* Get the file handle object and layer object */ + struct vpbe_fh *fh = q->priv_data; + struct vpbe_layer *layer = fh->layer; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n"); + + *size = layer->pix_fmt.sizeimage; + + /* Store number of buffers allocated in numbuffer member */ + if (*count < VPBE_DEFAULT_NUM_BUFS) + *count = layer->numbuffers = VPBE_DEFAULT_NUM_BUFS; + + return 0; +} + +/* + * vpbe_buffer_queue() + * This function adds the buffer to DMA queue + */ +static void vpbe_buffer_queue(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + /* Get the file handle object and layer object */ + struct vpbe_fh *fh = q->priv_data; + struct vpbe_layer *layer = fh->layer; + struct vpbe_display *disp = fh->disp_dev; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + unsigned long flags; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe_buffer_queue\n"); + + /* add the buffer to the DMA queue */ + spin_lock_irqsave(&disp->dma_queue_lock, flags); + list_add_tail(&vb->queue, &layer->dma_queue); + spin_unlock_irqrestore(&disp->dma_queue_lock, flags); + /* Change state of the buffer */ + vb->state = VIDEOBUF_QUEUED; +} + +/* + * vpbe_buffer_release() + * This function is called from the videobuf layer to free memory allocated to + * the buffers + */ +static void vpbe_buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + /* Get the file handle object and layer object */ + struct vpbe_fh *fh = q->priv_data; + struct vpbe_layer *layer = fh->layer; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe_buffer_release\n"); + + if (V4L2_MEMORY_USERPTR != layer->memory) + videobuf_dma_contig_free(q, vb); + + vb->state = VIDEOBUF_NEEDS_INIT; +} + +static struct videobuf_queue_ops video_qops = { + .buf_setup = vpbe_buffer_setup, + .buf_prepare = vpbe_buffer_prepare, + .buf_queue = vpbe_buffer_queue, + .buf_release = vpbe_buffer_release, +}; + +static +struct vpbe_layer* +_vpbe_display_get_other_win_layer(struct vpbe_display *disp_dev, + struct vpbe_layer *layer) +{ + enum vpbe_display_device_id thiswin, otherwin; + thiswin = layer->device_id; + + otherwin = (thiswin == VPBE_DISPLAY_DEVICE_0) ? + VPBE_DISPLAY_DEVICE_1 : VPBE_DISPLAY_DEVICE_0; + return disp_dev->dev[otherwin]; +} + +static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev, + struct vpbe_layer *layer) +{ + struct osd_layer_config *cfg = &layer->layer_info.config; + struct osd_state *osd_device = disp_dev->osd_device; + struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; + unsigned long addr; + int ret; + + addr = videobuf_to_dma_contig(layer->cur_frm); + /* Set address in the display registers */ + osd_device->ops.start_layer(osd_device, + layer->layer_info.id, + addr, + disp_dev->cbcr_ofst); + + ret = osd_device->ops.enable_layer(osd_device, + layer->layer_info.id, 0); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in enabling osd window layer 0\n"); + return -1; + } + + /* Enable the window */ + layer->layer_info.enable = 1; + if (cfg->pixfmt == PIXFMT_NV12) { + struct vpbe_layer *otherlayer = + _vpbe_display_get_other_win_layer(disp_dev, layer); + + ret = osd_device->ops.enable_layer(osd_device, + otherlayer->layer_info.id, 1); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in enabling osd window layer 1\n"); + return -1; + } + otherlayer->layer_info.enable = 1; + } + return 0; +} + +static void +vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev, + struct vpbe_layer *layer, + int expected_xsize, int expected_ysize) +{ + struct display_layer_info *layer_info = &layer->layer_info; + struct v4l2_pix_format *pixfmt = &layer->pix_fmt; + struct osd_layer_config *cfg = &layer->layer_info.config; + struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; + int calculated_xsize; + int h_exp = 0; + int v_exp = 0; + int h_scale; + int v_scale; + + v4l2_std_id standard_id = vpbe_dev->current_timings.timings.std_id; + + /* + * Application initially set the image format. Current display + * size is obtained from the vpbe display controller. expected_xsize + * and expected_ysize are set through S_CROP ioctl. Based on this, + * driver will calculate the scale factors for vertical and + * horizontal direction so that the image is displayed scaled + * and expanded. Application uses expansion to display the image + * in a square pixel. Otherwise it is displayed using displays + * pixel aspect ratio.It is expected that application chooses + * the crop coordinates for cropped or scaled display. if crop + * size is less than the image size, it is displayed cropped or + * it is displayed scaled and/or expanded. + * + * to begin with, set the crop window same as expected. Later we + * will override with scaled window size + */ + + cfg->xsize = pixfmt->width; + cfg->ysize = pixfmt->height; + layer_info->h_zoom = ZOOM_X1; /* no horizontal zoom */ + layer_info->v_zoom = ZOOM_X1; /* no horizontal zoom */ + layer_info->h_exp = H_EXP_OFF; /* no horizontal zoom */ + layer_info->v_exp = V_EXP_OFF; /* no horizontal zoom */ + + if (pixfmt->width < expected_xsize) { + h_scale = vpbe_dev->current_timings.xres / pixfmt->width; + if (h_scale < 2) + h_scale = 1; + else if (h_scale >= 4) + h_scale = 4; + else + h_scale = 2; + cfg->xsize *= h_scale; + if (cfg->xsize < expected_xsize) { + if ((standard_id & V4L2_STD_525_60) || + (standard_id & V4L2_STD_625_50)) { + calculated_xsize = (cfg->xsize * + VPBE_DISPLAY_H_EXP_RATIO_N) / + VPBE_DISPLAY_H_EXP_RATIO_D; + if (calculated_xsize <= expected_xsize) { + h_exp = 1; + cfg->xsize = calculated_xsize; + } + } + } + if (h_scale == 2) + layer_info->h_zoom = ZOOM_X2; + else if (h_scale == 4) + layer_info->h_zoom = ZOOM_X4; + if (h_exp) + layer_info->h_exp = H_EXP_9_OVER_8; + } else { + /* no scaling, only cropping. Set display area to crop area */ + cfg->xsize = expected_xsize; + } + + if (pixfmt->height < expected_ysize) { + v_scale = expected_ysize / pixfmt->height; + if (v_scale < 2) + v_scale = 1; + else if (v_scale >= 4) + v_scale = 4; + else + v_scale = 2; + cfg->ysize *= v_scale; + if (cfg->ysize < expected_ysize) { + if ((standard_id & V4L2_STD_625_50)) { + calculated_xsize = (cfg->ysize * + VPBE_DISPLAY_V_EXP_RATIO_N) / + VPBE_DISPLAY_V_EXP_RATIO_D; + if (calculated_xsize <= expected_ysize) { + v_exp = 1; + cfg->ysize = calculated_xsize; + } + } + } + if (v_scale == 2) + layer_info->v_zoom = ZOOM_X2; + else if (v_scale == 4) + layer_info->v_zoom = ZOOM_X4; + if (v_exp) + layer_info->h_exp = V_EXP_6_OVER_5; + } else { + /* no scaling, only cropping. Set display area to crop area */ + cfg->ysize = expected_ysize; + } + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "crop display xsize = %d, ysize = %d\n", + cfg->xsize, cfg->ysize); +} + +static void vpbe_disp_adj_position(struct vpbe_display *disp_dev, + struct vpbe_layer *layer, + int top, int left) +{ + struct osd_layer_config *cfg = &layer->layer_info.config; + struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; + + cfg->xpos = min((unsigned int)left, + vpbe_dev->current_timings.xres - cfg->xsize); + cfg->ypos = min((unsigned int)top, + vpbe_dev->current_timings.yres - cfg->ysize); + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "new xpos = %d, ypos = %d\n", + cfg->xpos, cfg->ypos); +} + +static void vpbe_disp_check_window_params(struct vpbe_display *disp_dev, + struct v4l2_rect *c) +{ + struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; + + if ((c->width == 0) || + ((c->width + c->left) > vpbe_dev->current_timings.xres)) + c->width = vpbe_dev->current_timings.xres - c->left; + + if ((c->height == 0) || ((c->height + c->top) > + vpbe_dev->current_timings.yres)) + c->height = vpbe_dev->current_timings.yres - c->top; + + /* window height must be even for interlaced display */ + if (vpbe_dev->current_timings.interlaced) + c->height &= (~0x01); + +} + +/** + * vpbe_try_format() + * If user application provides width and height, and have bytesperline set + * to zero, driver calculates bytesperline and sizeimage based on hardware + * limits. + */ +static int vpbe_try_format(struct vpbe_display *disp_dev, + struct v4l2_pix_format *pixfmt, int check) +{ + struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; + int min_height = 1; + int min_width = 32; + int max_height; + int max_width; + int bpp; + + if ((pixfmt->pixelformat != V4L2_PIX_FMT_UYVY) && + (pixfmt->pixelformat != V4L2_PIX_FMT_NV12)) + /* choose default as V4L2_PIX_FMT_UYVY */ + pixfmt->pixelformat = V4L2_PIX_FMT_UYVY; + + /* Check the field format */ + if ((pixfmt->field != V4L2_FIELD_INTERLACED) && + (pixfmt->field != V4L2_FIELD_NONE)) { + if (vpbe_dev->current_timings.interlaced) + pixfmt->field = V4L2_FIELD_INTERLACED; + else + pixfmt->field = V4L2_FIELD_NONE; + } + + if (pixfmt->field == V4L2_FIELD_INTERLACED) + min_height = 2; + + if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) + bpp = 1; + else + bpp = 2; + + max_width = vpbe_dev->current_timings.xres; + max_height = vpbe_dev->current_timings.yres; + + min_width /= bpp; + + if (!pixfmt->width || (pixfmt->width < min_width) || + (pixfmt->width > max_width)) { + pixfmt->width = vpbe_dev->current_timings.xres; + } + + if (!pixfmt->height || (pixfmt->height < min_height) || + (pixfmt->height > max_height)) { + pixfmt->height = vpbe_dev->current_timings.yres; + } + + if (pixfmt->bytesperline < (pixfmt->width * bpp)) + pixfmt->bytesperline = pixfmt->width * bpp; + + /* Make the bytesperline 32 byte aligned */ + pixfmt->bytesperline = ((pixfmt->width * bpp + 31) & ~31); + + if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) + pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height + + (pixfmt->bytesperline * pixfmt->height >> 1); + else + pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; + + return 0; +} + +static int vpbe_display_g_priority(struct file *file, void *priv, + enum v4l2_priority *p) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_layer *layer = fh->layer; + + *p = v4l2_prio_max(&layer->prio); + + return 0; +} + +static int vpbe_display_s_priority(struct file *file, void *priv, + enum v4l2_priority p) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_layer *layer = fh->layer; + int ret; + + ret = v4l2_prio_change(&layer->prio, &fh->prio, p); + + return ret; +} + +static int vpbe_display_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + + cap->version = VPBE_DISPLAY_VERSION_CODE; + cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + strlcpy(cap->driver, VPBE_DISPLAY_DRIVER, sizeof(cap->driver)); + strlcpy(cap->bus_info, "platform", sizeof(cap->bus_info)); + strlcpy(cap->card, vpbe_dev->cfg->module_name, sizeof(cap->card)); + + return 0; +} + +static int vpbe_display_s_crop(struct file *file, void *priv, + struct v4l2_crop *crop) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_layer *layer = fh->layer; + struct vpbe_display *disp_dev = fh->disp_dev; + struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; + struct osd_layer_config *cfg = &layer->layer_info.config; + struct osd_state *osd_device = disp_dev->osd_device; + struct v4l2_rect *rect = &crop->c; + int ret; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_S_CROP, layer id = %d\n", layer->device_id); + + if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n"); + return -EINVAL; + } + + if (rect->top < 0) + rect->top = 0; + if (rect->left < 0) + rect->left = 0; + + vpbe_disp_check_window_params(disp_dev, rect); + + osd_device->ops.get_layer_config(osd_device, + layer->layer_info.id, cfg); + + vpbe_disp_calculate_scale_factor(disp_dev, layer, + rect->width, + rect->height); + vpbe_disp_adj_position(disp_dev, layer, rect->top, + rect->left); + ret = osd_device->ops.set_layer_config(osd_device, + layer->layer_info.id, cfg); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in set layer config:\n"); + return -EINVAL; + } + + /* apply zooming and h or v expansion */ + osd_device->ops.set_zoom(osd_device, + layer->layer_info.id, + layer->layer_info.h_zoom, + layer->layer_info.v_zoom); + ret = osd_device->ops.set_vid_expansion(osd_device, + layer->layer_info.h_exp, + layer->layer_info.v_exp); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in set vid expansion:\n"); + return -EINVAL; + } + + if ((layer->layer_info.h_zoom != ZOOM_X1) || + (layer->layer_info.v_zoom != ZOOM_X1) || + (layer->layer_info.h_exp != H_EXP_OFF) || + (layer->layer_info.v_exp != V_EXP_OFF)) + /* Enable expansion filter */ + osd_device->ops.set_interpolation_filter(osd_device, 1); + else + osd_device->ops.set_interpolation_filter(osd_device, 0); + + return 0; +} + +static int vpbe_display_g_crop(struct file *file, void *priv, + struct v4l2_crop *crop) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_layer *layer = fh->layer; + struct osd_layer_config *cfg = &layer->layer_info.config; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + struct osd_state *osd_device = fh->disp_dev->osd_device; + struct v4l2_rect *rect = &crop->c; + int ret; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_G_CROP, layer id = %d\n", + layer->device_id); + + if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n"); + ret = -EINVAL; + } + osd_device->ops.get_layer_config(osd_device, + layer->layer_info.id, cfg); + rect->top = cfg->ypos; + rect->left = cfg->xpos; + rect->width = cfg->xsize; + rect->height = cfg->ysize; + + return 0; +} + +static int vpbe_display_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cropcap) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n"); + + cropcap->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + cropcap->bounds.left = 0; + cropcap->bounds.top = 0; + cropcap->bounds.width = vpbe_dev->current_timings.xres; + cropcap->bounds.height = vpbe_dev->current_timings.yres; + cropcap->pixelaspect = vpbe_dev->current_timings.aspect; + cropcap->defrect = cropcap->bounds; + return 0; +} + +static int vpbe_display_g_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_layer *layer = fh->layer; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_G_FMT, layer id = %d\n", + layer->device_id); + + /* If buffer type is video output */ + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n"); + return -EINVAL; + } + /* Fill in the information about format */ + fmt->fmt.pix = layer->pix_fmt; + + return 0; +} + +static int vpbe_display_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *fmt) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_layer *layer = fh->layer; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + unsigned int index = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_ENUM_FMT, layer id = %d\n", + layer->device_id); + if (fmt->index > 1) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid format index\n"); + return -EINVAL; + } + + /* Fill in the information about format */ + index = fmt->index; + memset(fmt, 0, sizeof(*fmt)); + fmt->index = index; + fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + if (index == 0) { + strcpy(fmt->description, "YUV 4:2:2 - UYVY"); + fmt->pixelformat = V4L2_PIX_FMT_UYVY; + } else { + strcpy(fmt->description, "Y/CbCr 4:2:0"); + fmt->pixelformat = V4L2_PIX_FMT_NV12; + } + + return 0; +} + +static int vpbe_display_s_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_layer *layer = fh->layer; + struct vpbe_display *disp_dev = fh->disp_dev; + struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; + struct osd_layer_config *cfg = &layer->layer_info.config; + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + struct osd_state *osd_device = disp_dev->osd_device; + int ret; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_S_FMT, layer id = %d\n", + layer->device_id); + + /* If streaming is started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "invalid type\n"); + return -EINVAL; + } + /* Check for valid pixel format */ + ret = vpbe_try_format(disp_dev, pixfmt, 1); + if (ret) + return ret; + + /* YUV420 is requested, check availability of the + other video window */ + + layer->pix_fmt = *pixfmt; + + /* Get osd layer config */ + osd_device->ops.get_layer_config(osd_device, + layer->layer_info.id, cfg); + /* Store the pixel format in the layer object */ + cfg->xsize = pixfmt->width; + cfg->ysize = pixfmt->height; + cfg->line_length = pixfmt->bytesperline; + cfg->ypos = 0; + cfg->xpos = 0; + cfg->interlaced = vpbe_dev->current_timings.interlaced; + + if (V4L2_PIX_FMT_UYVY == pixfmt->pixelformat) + cfg->pixfmt = PIXFMT_YCbCrI; + + /* Change of the default pixel format for both video windows */ + if (V4L2_PIX_FMT_NV12 == pixfmt->pixelformat) { + struct vpbe_layer *otherlayer; + cfg->pixfmt = PIXFMT_NV12; + otherlayer = _vpbe_display_get_other_win_layer(disp_dev, + layer); + otherlayer->layer_info.config.pixfmt = PIXFMT_NV12; + } + + /* Set the layer config in the osd window */ + ret = osd_device->ops.set_layer_config(osd_device, + layer->layer_info.id, cfg); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in S_FMT params:\n"); + return -EINVAL; + } + + /* Readback and fill the local copy of current pix format */ + osd_device->ops.get_layer_config(osd_device, + layer->layer_info.id, cfg); + + return 0; +} + +static int vpbe_display_try_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display *disp_dev = fh->disp_dev; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_TRY_FMT\n"); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n"); + return -EINVAL; + } + + /* Check for valid field format */ + return vpbe_try_format(disp_dev, pixfmt, 0); + +} + +/** + * vpbe_display_s_std - Set the given standard in the encoder + * + * Sets the standard if supported by the current encoder. Return the status. + * 0 - success & -EINVAL on error + */ +static int vpbe_display_s_std(struct file *file, void *priv, + v4l2_std_id *std_id) +{ + struct vpbe_fh *fh = priv; + struct vpbe_layer *layer = fh->layer; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + int ret; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_STD\n"); + + /* If streaming is started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + if (NULL != vpbe_dev->ops.s_std) { + ret = vpbe_dev->ops.s_std(vpbe_dev, std_id); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Failed to set standard for sub devices\n"); + return -EINVAL; + } + } else { + return -EINVAL; + } + + return 0; +} + +/** + * vpbe_display_g_std - Get the standard in the current encoder + * + * Get the standard in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_display_g_std(struct file *file, void *priv, + v4l2_std_id *std_id) +{ + struct vpbe_fh *fh = priv; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_STD\n"); + + /* Get the standard from the current encoder */ + if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) { + *std_id = vpbe_dev->current_timings.timings.std_id; + return 0; + } + + return -EINVAL; +} + +/** + * vpbe_display_enum_output - enumerate outputs + * + * Enumerates the outputs available at the vpbe display + * returns the status, -EINVAL if end of output list + */ +static int vpbe_display_enum_output(struct file *file, void *priv, + struct v4l2_output *output) +{ + struct vpbe_fh *fh = priv; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + int ret; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_OUTPUT\n"); + + /* Enumerate outputs */ + + if (NULL == vpbe_dev->ops.enum_outputs) + return -EINVAL; + + ret = vpbe_dev->ops.enum_outputs(vpbe_dev, output); + if (ret) { + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "Failed to enumerate outputs\n"); + return -EINVAL; + } + + return 0; +} + +/** + * vpbe_display_s_output - Set output to + * the output specified by the index + */ +static int vpbe_display_s_output(struct file *file, void *priv, + unsigned int i) +{ + struct vpbe_fh *fh = priv; + struct vpbe_layer *layer = fh->layer; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + int ret; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_OUTPUT\n"); + /* If streaming is started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + if (NULL == vpbe_dev->ops.set_output) + return -EINVAL; + + ret = vpbe_dev->ops.set_output(vpbe_dev, i); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Failed to set output for sub devices\n"); + return -EINVAL; + } + + return 0; +} + +/** + * vpbe_display_g_output - Get output from subdevice + * for a given by the index + */ +static int vpbe_display_g_output(struct file *file, void *priv, + unsigned int *i) +{ + struct vpbe_fh *fh = priv; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_OUTPUT\n"); + /* Get the standard from the current encoder */ + *i = vpbe_dev->current_out_index; + + return 0; +} + +/** + * vpbe_display_enum_dv_presets - Enumerate the dv presets + * + * enum the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int +vpbe_display_enum_dv_presets(struct file *file, void *priv, + struct v4l2_dv_enum_preset *preset) +{ + struct vpbe_fh *fh = priv; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + int ret; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_PRESETS\n"); + + /* Enumerate outputs */ + if (NULL == vpbe_dev->ops.enum_dv_presets) + return -EINVAL; + + ret = vpbe_dev->ops.enum_dv_presets(vpbe_dev, preset); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Failed to enumerate dv presets info\n"); + return -EINVAL; + } + + return 0; +} + +/** + * vpbe_display_s_dv_preset - Set the dv presets + * + * Set the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int +vpbe_display_s_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *preset) +{ + struct vpbe_fh *fh = priv; + struct vpbe_layer *layer = fh->layer; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + int ret; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_PRESETS\n"); + + + /* If streaming is started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + + /* Set the given standard in the encoder */ + if (NULL != vpbe_dev->ops.s_dv_preset) + return -EINVAL; + + ret = vpbe_dev->ops.s_dv_preset(vpbe_dev, preset); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Failed to set the dv presets info\n"); + return -EINVAL; + } + /* set the current norm to zero to be consistent. If STD is used + * v4l2 layer will set the norm properly on successful s_std call + */ + layer->video_dev.current_norm = 0; + + return 0; +} + +/** + * vpbe_display_g_dv_preset - Set the dv presets + * + * Get the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int +vpbe_display_g_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *dv_preset) +{ + struct vpbe_fh *fh = priv; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_PRESETS\n"); + + /* Get the given standard in the encoder */ + + if (vpbe_dev->current_timings.timings_type & + VPBE_ENC_DV_PRESET) { + dv_preset->preset = + vpbe_dev->current_timings.timings.dv_preset; + } else { + return -EINVAL; + } + + return 0; +} + +static int vpbe_display_streamoff(struct file *file, void *priv, + enum v4l2_buf_type buf_type) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_layer *layer = fh->layer; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + struct osd_state *osd_device = fh->disp_dev->osd_device; + int ret; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_STREAMOFF,layer id = %d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* If io is allowed for this file handle, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); + return -EACCES; + } + + /* If streaming is not started, return error */ + if (!layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "streaming not started in layer" + " id = %d\n", layer->device_id); + return -EINVAL; + } + + osd_device->ops.disable_layer(osd_device, + layer->layer_info.id); + layer->started = 0; + ret = videobuf_streamoff(&layer->buffer_queue); + + return ret; +} + +static int vpbe_display_streamon(struct file *file, void *priv, + enum v4l2_buf_type buf_type) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_layer *layer = fh->layer; + struct vpbe_display *disp_dev = fh->disp_dev; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + struct osd_state *osd_device = disp_dev->osd_device; + int ret; + + osd_device->ops.disable_layer(osd_device, + layer->layer_info.id); + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_STREAMON, layerid=%d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* If file handle is not allowed IO, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); + return -EACCES; + } + /* If Streaming is already started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "layer is already streaming\n"); + return -EBUSY; + } + + /* + * Call videobuf_streamon to start streaming + * in videobuf + */ + ret = videobuf_streamon(&layer->buffer_queue); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "error in videobuf_streamon\n"); + return ret; + } + /* If buffer queue is empty, return error */ + if (list_empty(&layer->dma_queue)) { + v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n"); + goto streamoff; + } + /* Get the next frame from the buffer queue */ + layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next, + struct videobuf_buffer, queue); + /* Remove buffer from the buffer queue */ + list_del(&layer->cur_frm->queue); + /* Mark state of the current frame to active */ + layer->cur_frm->state = VIDEOBUF_ACTIVE; + /* Initialize field_id and started member */ + layer->field_id = 0; + + /* Set parameters in OSD and VENC */ + ret = vpbe_set_osd_display_params(disp_dev, layer); + if (ret < 0) + goto streamoff; + + /* + * if request format is yuv420 semiplanar, need to + * enable both video windows + */ + layer->started = 1; + + layer->layer_first_int = 1; + + return ret; +streamoff: + ret = videobuf_streamoff(&layer->buffer_queue); + return ret; +} + +static int vpbe_display_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_layer *layer = fh->layer; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + int ret; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_DQBUF, layer id = %d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + /* If this file handle is not allowed to do IO, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); + return -EACCES; + } + if (file->f_flags & O_NONBLOCK) + /* Call videobuf_dqbuf for non blocking mode */ + ret = videobuf_dqbuf(&layer->buffer_queue, buf, 1); + else + /* Call videobuf_dqbuf for blocking mode */ + ret = videobuf_dqbuf(&layer->buffer_queue, buf, 0); + + return ret; +} + +static int vpbe_display_qbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_layer *layer = fh->layer; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_QBUF, layer id = %d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != p->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* If this file handle is not allowed to do IO, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); + return -EACCES; + } + + return videobuf_qbuf(&layer->buffer_queue, p); +} + +static int vpbe_display_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_layer *layer = fh->layer; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + int ret; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_QUERYBUF, layer id = %d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* Call videobuf_querybuf to get information */ + ret = videobuf_querybuf(&layer->buffer_queue, buf); + + return ret; +} + +static int vpbe_display_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *req_buf) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_layer *layer = fh->layer; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + int ret; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_reqbufs\n"); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* If io users of the layer is not zero, return error */ + if (0 != layer->io_usrs) { + v4l2_err(&vpbe_dev->v4l2_dev, "not IO user\n"); + return -EBUSY; + } + /* Initialize videobuf queue as per the buffer type */ + videobuf_queue_dma_contig_init(&layer->buffer_queue, + &video_qops, + vpbe_dev->pdev, + &layer->irqlock, + V4L2_BUF_TYPE_VIDEO_OUTPUT, + layer->pix_fmt.field, + sizeof(struct videobuf_buffer), + fh, NULL); + + /* Set io allowed member of file handle to TRUE */ + fh->io_allowed = 1; + /* Increment io usrs member of layer object to 1 */ + layer->io_usrs = 1; + /* Store type of memory requested in layer object */ + layer->memory = req_buf->memory; + /* Initialize buffer queue */ + INIT_LIST_HEAD(&layer->dma_queue); + /* Allocate buffers */ + ret = videobuf_reqbufs(&layer->buffer_queue, req_buf); + + return ret; +} + +/* + * vpbe_display_mmap() + * It is used to map kernel space buffers into user spaces + */ +static int vpbe_display_mmap(struct file *filep, struct vm_area_struct *vma) +{ + /* Get the layer object and file handle object */ + struct vpbe_fh *fh = filep->private_data; + struct vpbe_layer *layer = fh->layer; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_mmap\n"); + + return videobuf_mmap_mapper(&layer->buffer_queue, vma); +} + +/* vpbe_display_poll(): It is used for select/poll system call + */ +static unsigned int vpbe_display_poll(struct file *filep, poll_table *wait) +{ + struct vpbe_fh *fh = filep->private_data; + struct vpbe_layer *layer = fh->layer; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + unsigned int err = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_poll\n"); + if (layer->started) + err = videobuf_poll_stream(filep, &layer->buffer_queue, wait); + return err; +} + +/* + * vpbe_display_open() + * It creates object of file handle structure and stores it in private_data + * member of filepointer + */ +static int vpbe_display_open(struct file *file) +{ + struct vpbe_fh *fh = NULL; + struct vpbe_layer *layer = video_drvdata(file); + struct vpbe_display *disp_dev = layer->disp_dev; + struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; + struct osd_state *osd_device = disp_dev->osd_device; + int err; + + /* Allocate memory for the file handle object */ + fh = kmalloc(sizeof(struct vpbe_fh), GFP_KERNEL); + if (fh == NULL) { + v4l2_err(&vpbe_dev->v4l2_dev, + "unable to allocate memory for file handle object\n"); + return -ENOMEM; + } + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe display open plane = %d\n", + layer->device_id); + + /* store pointer to fh in private_data member of filep */ + file->private_data = fh; + fh->layer = layer; + fh->disp_dev = disp_dev; + + if (!layer->usrs) { + + /* First claim the layer for this device */ + err = osd_device->ops.request_layer(osd_device, + layer->layer_info.id); + if (err < 0) { + /* Couldn't get layer */ + v4l2_err(&vpbe_dev->v4l2_dev, + "Display Manager failed to allocate layer\n"); + kfree(fh); + return -EINVAL; + } + } + /* Increment layer usrs counter */ + layer->usrs++; + /* Set io_allowed member to false */ + fh->io_allowed = 0; + /* Initialize priority of this instance to default priority */ + fh->prio = V4L2_PRIORITY_UNSET; + v4l2_prio_open(&layer->prio, &fh->prio); + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe display device opened successfully\n"); + return 0; +} + +/* + * vpbe_display_release() + * This function deletes buffer queue, frees the buffers and the davinci + * display file * handle + */ +static int vpbe_display_release(struct file *file) +{ + /* Get the layer object and file handle object */ + struct vpbe_fh *fh = file->private_data; + struct vpbe_layer *layer = fh->layer; + struct osd_layer_config *cfg = &layer->layer_info.config; + struct vpbe_display *disp_dev = fh->disp_dev; + struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; + struct osd_state *osd_device = disp_dev->osd_device; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_release\n"); + + /* if this instance is doing IO */ + if (fh->io_allowed) { + /* Reset io_usrs member of layer object */ + layer->io_usrs = 0; + + osd_device->ops.disable_layer(osd_device, + layer->layer_info.id); + layer->started = 0; + /* Free buffers allocated */ + videobuf_queue_cancel(&layer->buffer_queue); + videobuf_mmap_free(&layer->buffer_queue); + } + + /* Decrement layer usrs counter */ + layer->usrs--; + /* If this file handle has initialize encoder device, reset it */ + if (!layer->usrs) { + if (cfg->pixfmt == PIXFMT_NV12) { + struct vpbe_layer *otherlayer; + otherlayer = + _vpbe_display_get_other_win_layer(disp_dev, layer); + osd_device->ops.disable_layer(osd_device, + otherlayer->layer_info.id); + osd_device->ops.release_layer(osd_device, + otherlayer->layer_info.id); + } + osd_device->ops.disable_layer(osd_device, + layer->layer_info.id); + osd_device->ops.release_layer(osd_device, + layer->layer_info.id); + } + /* Close the priority */ + v4l2_prio_close(&layer->prio, fh->prio); + file->private_data = NULL; + + /* Free memory allocated to file handle object */ + kfree(fh); + + disp_dev->cbcr_ofst = 0; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vpbe_display_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct v4l2_dbg_match *match = ®->match; + + if (match->type >= 2) { + v4l2_subdev_call(vpbe_dev->venc, + core, + g_register, + reg); + } + + return 0; +} + +static int vpbe_display_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + return 0; +} +#endif + +/* vpbe capture ioctl operations */ +static const struct v4l2_ioctl_ops vpbe_ioctl_ops = { + .vidioc_querycap = vpbe_display_querycap, + .vidioc_g_fmt_vid_out = vpbe_display_g_fmt, + .vidioc_enum_fmt_vid_out = vpbe_display_enum_fmt, + .vidioc_s_fmt_vid_out = vpbe_display_s_fmt, + .vidioc_try_fmt_vid_out = vpbe_display_try_fmt, + .vidioc_reqbufs = vpbe_display_reqbufs, + .vidioc_querybuf = vpbe_display_querybuf, + .vidioc_qbuf = vpbe_display_qbuf, + .vidioc_dqbuf = vpbe_display_dqbuf, + .vidioc_streamon = vpbe_display_streamon, + .vidioc_streamoff = vpbe_display_streamoff, + .vidioc_cropcap = vpbe_display_cropcap, + .vidioc_g_crop = vpbe_display_g_crop, + .vidioc_s_crop = vpbe_display_s_crop, + .vidioc_g_priority = vpbe_display_g_priority, + .vidioc_s_priority = vpbe_display_s_priority, + .vidioc_s_std = vpbe_display_s_std, + .vidioc_g_std = vpbe_display_g_std, + .vidioc_enum_output = vpbe_display_enum_output, + .vidioc_s_output = vpbe_display_s_output, + .vidioc_g_output = vpbe_display_g_output, + .vidioc_s_dv_preset = vpbe_display_s_dv_preset, + .vidioc_g_dv_preset = vpbe_display_g_dv_preset, + .vidioc_enum_dv_presets = vpbe_display_enum_dv_presets, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vpbe_display_g_register, + .vidioc_s_register = vpbe_display_s_register, +#endif +}; + +static struct v4l2_file_operations vpbe_fops = { + .owner = THIS_MODULE, + .open = vpbe_display_open, + .release = vpbe_display_release, + .unlocked_ioctl = video_ioctl2, + .mmap = vpbe_display_mmap, + .poll = vpbe_display_poll +}; + +static int vpbe_device_get(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct vpbe_display *vpbe_disp = data; + + if (strcmp("vpbe_controller", pdev->name) == 0) + vpbe_disp->vpbe_dev = platform_get_drvdata(pdev); + + if (strcmp("vpbe-osd", pdev->name) == 0) + vpbe_disp->osd_device = platform_get_drvdata(pdev); + + return 0; +} + +static __devinit int init_vpbe_layer(int i, struct vpbe_display *disp_dev, + struct platform_device *pdev) +{ + struct vpbe_layer *vpbe_display_layer = NULL; + struct video_device *vbd = NULL; + + /* Allocate memory for four plane display objects */ + + disp_dev->dev[i] = + kzalloc(sizeof(struct vpbe_layer), GFP_KERNEL); + + /* If memory allocation fails, return error */ + if (!disp_dev->dev[i]) { + printk(KERN_ERR "ran out of memory\n"); + return -ENOMEM; + } + spin_lock_init(&disp_dev->dev[i]->irqlock); + mutex_init(&disp_dev->dev[i]->opslock); + + /* Get the pointer to the layer object */ + vpbe_display_layer = disp_dev->dev[i]; + vbd = &vpbe_display_layer->video_dev; + /* Initialize field of video device */ + vbd->release = video_device_release_empty; + vbd->fops = &vpbe_fops; + vbd->ioctl_ops = &vpbe_ioctl_ops; + vbd->minor = -1; + vbd->v4l2_dev = &disp_dev->vpbe_dev->v4l2_dev; + vbd->lock = &vpbe_display_layer->opslock; + + if (disp_dev->vpbe_dev->current_timings.timings_type & + VPBE_ENC_STD) { + vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50); + vbd->current_norm = + disp_dev->vpbe_dev-> + current_timings.timings.std_id; + } else + vbd->current_norm = 0; + + snprintf(vbd->name, sizeof(vbd->name), + "DaVinci_VPBE Display_DRIVER_V%d.%d.%d", + (VPBE_DISPLAY_VERSION_CODE >> 16) & 0xff, + (VPBE_DISPLAY_VERSION_CODE >> 8) & 0xff, + (VPBE_DISPLAY_VERSION_CODE) & 0xff); + + vpbe_display_layer->device_id = i; + + vpbe_display_layer->layer_info.id = + ((i == VPBE_DISPLAY_DEVICE_0) ? WIN_VID0 : WIN_VID1); + + /* Initialize prio member of layer object */ + v4l2_prio_init(&vpbe_display_layer->prio); + + return 0; +} + +static __devinit int register_device(struct vpbe_layer *vpbe_display_layer, + struct vpbe_display *disp_dev, + struct platform_device *pdev) { + int err; + + v4l2_info(&disp_dev->vpbe_dev->v4l2_dev, + "Trying to register VPBE display device.\n"); + v4l2_info(&disp_dev->vpbe_dev->v4l2_dev, + "layer=%x,layer->video_dev=%x\n", + (int)vpbe_display_layer, + (int)&vpbe_display_layer->video_dev); + + err = video_register_device(&vpbe_display_layer->video_dev, + VFL_TYPE_GRABBER, + -1); + if (err) + return -ENODEV; + + vpbe_display_layer->disp_dev = disp_dev; + /* set the driver data in platform device */ + platform_set_drvdata(pdev, disp_dev); + video_set_drvdata(&vpbe_display_layer->video_dev, + vpbe_display_layer); + + return 0; +} + + + +/* + * vpbe_display_probe() + * This function creates device entries by register itself to the V4L2 driver + * and initializes fields of each layer objects + */ +static __devinit int vpbe_display_probe(struct platform_device *pdev) +{ + struct vpbe_layer *vpbe_display_layer; + struct vpbe_display *disp_dev; + struct resource *res = NULL; + int k; + int i; + int err; + int irq; + + printk(KERN_DEBUG "vpbe_display_probe\n"); + /* Allocate memory for vpbe_display */ + disp_dev = kzalloc(sizeof(struct vpbe_display), GFP_KERNEL); + if (!disp_dev) { + printk(KERN_ERR "ran out of memory\n"); + return -ENOMEM; + } + + spin_lock_init(&disp_dev->dma_queue_lock); + /* + * Scan all the platform devices to find the vpbe + * controller device and get the vpbe_dev object + */ + err = bus_for_each_dev(&platform_bus_type, NULL, disp_dev, + vpbe_device_get); + if (err < 0) + return err; + /* Initialize the vpbe display controller */ + if (NULL != disp_dev->vpbe_dev->ops.initialize) { + err = disp_dev->vpbe_dev->ops.initialize(&pdev->dev, + disp_dev->vpbe_dev); + if (err) { + v4l2_err(&disp_dev->vpbe_dev->v4l2_dev, + "Error initing vpbe\n"); + err = -ENOMEM; + goto probe_out; + } + } + + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + if (init_vpbe_layer(i, disp_dev, pdev)) { + err = -ENODEV; + goto probe_out; + } + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + v4l2_err(&disp_dev->vpbe_dev->v4l2_dev, + "Unable to get VENC interrupt resource\n"); + err = -ENODEV; + goto probe_out; + } + + irq = res->start; + if (request_irq(irq, venc_isr, IRQF_DISABLED, VPBE_DISPLAY_DRIVER, + disp_dev)) { + v4l2_err(&disp_dev->vpbe_dev->v4l2_dev, + "Unable to request interrupt\n"); + err = -ENODEV; + goto probe_out; + } + + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + if (register_device(disp_dev->dev[i], disp_dev, pdev)) { + err = -ENODEV; + goto probe_out; + } + } + + printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n"); + return 0; + +probe_out: + free_irq(res->start, disp_dev); + for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) { + /* Get the pointer to the layer object */ + vpbe_display_layer = disp_dev->dev[k]; + /* Unregister video device */ + if (vpbe_display_layer) { + video_unregister_device( + &vpbe_display_layer->video_dev); + kfree(disp_dev->dev[k]); + } + } + kfree(disp_dev); + return err; +} + +/* + * vpbe_display_remove() + * It un-register hardware layer from V4L2 driver + */ +static int vpbe_display_remove(struct platform_device *pdev) +{ + struct vpbe_layer *vpbe_display_layer; + struct vpbe_display *disp_dev = platform_get_drvdata(pdev); + struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; + struct resource *res; + int i; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n"); + + /* unregister irq */ + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + free_irq(res->start, disp_dev); + + /* deinitialize the vpbe display controller */ + if (NULL != vpbe_dev->ops.deinitialize) + vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev); + /* un-register device */ + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + /* Get the pointer to the layer object */ + vpbe_display_layer = disp_dev->dev[i]; + /* Unregister video device */ + video_unregister_device(&vpbe_display_layer->video_dev); + + } + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + kfree(disp_dev->dev[i]); + disp_dev->dev[i] = NULL; + } + + return 0; +} + +static struct platform_driver vpbe_display_driver = { + .driver = { + .name = VPBE_DISPLAY_DRIVER, + .owner = THIS_MODULE, + .bus = &platform_bus_type, + }, + .probe = vpbe_display_probe, + .remove = __devexit_p(vpbe_display_remove), +}; + +/* + * vpbe_display_init() + * This function registers device and driver to the kernel, requests irq + * handler and allocates memory for layer objects + */ +static __devinit int vpbe_display_init(void) +{ + int err; + + printk(KERN_DEBUG "vpbe_display_init\n"); + + /* Register driver to the kernel */ + err = platform_driver_register(&vpbe_display_driver); + if (0 != err) + return err; + + printk(KERN_DEBUG "vpbe_display_init:" + "VPBE V4L2 Display Driver V1.0 loaded\n"); + return 0; +} + +/* + * vpbe_display_cleanup() + * This function un-registers device and driver to the kernel, frees requested + * irq handler and de-allocates memory allocated for layer objects. + */ +static void vpbe_display_cleanup(void) +{ + printk(KERN_DEBUG "vpbe_display_cleanup\n"); + + /* platform driver unregister */ + platform_driver_unregister(&vpbe_display_driver); +} + +/* Function for module initialization and cleanup */ +module_init(vpbe_display_init); +module_exit(vpbe_display_cleanup); + +MODULE_DESCRIPTION("TI DM644x/DM355/DM365 VPBE Display controller"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/media/video/davinci/vpbe_osd.c b/drivers/media/video/davinci/vpbe_osd.c new file mode 100644 index 0000000000000000000000000000000000000000..5352884998f5bb7542157ee0d938ae262815617e --- /dev/null +++ b/drivers/media/video/davinci/vpbe_osd.c @@ -0,0 +1,1231 @@ +/* + * Copyright (C) 2007-2010 Texas Instruments Inc + * Copyright (C) 2007 MontaVista Software, Inc. + * + * Andy Lowe (alowe@mvista.com), MontaVista Software + * - Initial version + * Murali Karicheri (mkaricheri@gmail.com), Texas Instruments Ltd. + * - ported to sub device interface + * + * 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 version 2. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "vpbe_osd_regs.h" + +#define MODULE_NAME VPBE_OSD_SUBDEV_NAME + +/* register access routines */ +static inline u32 osd_read(struct osd_state *sd, u32 offset) +{ + struct osd_state *osd = sd; + + return readl(osd->osd_base + offset); +} + +static inline u32 osd_write(struct osd_state *sd, u32 val, u32 offset) +{ + struct osd_state *osd = sd; + + writel(val, osd->osd_base + offset); + + return val; +} + +static inline u32 osd_set(struct osd_state *sd, u32 mask, u32 offset) +{ + struct osd_state *osd = sd; + + u32 addr = osd->osd_base + offset; + u32 val = readl(addr) | mask; + + writel(val, addr); + + return val; +} + +static inline u32 osd_clear(struct osd_state *sd, u32 mask, u32 offset) +{ + struct osd_state *osd = sd; + + u32 addr = osd->osd_base + offset; + u32 val = readl(addr) & ~mask; + + writel(val, addr); + + return val; +} + +static inline u32 osd_modify(struct osd_state *sd, u32 mask, u32 val, + u32 offset) +{ + struct osd_state *osd = sd; + + u32 addr = osd->osd_base + offset; + u32 new_val = (readl(addr) & ~mask) | (val & mask); + + writel(new_val, addr); + + return new_val; +} + +/* define some macros for layer and pixfmt classification */ +#define is_osd_win(layer) (((layer) == WIN_OSD0) || ((layer) == WIN_OSD1)) +#define is_vid_win(layer) (((layer) == WIN_VID0) || ((layer) == WIN_VID1)) +#define is_rgb_pixfmt(pixfmt) \ + (((pixfmt) == PIXFMT_RGB565) || ((pixfmt) == PIXFMT_RGB888)) +#define is_yc_pixfmt(pixfmt) \ + (((pixfmt) == PIXFMT_YCbCrI) || ((pixfmt) == PIXFMT_YCrCbI) || \ + ((pixfmt) == PIXFMT_NV12)) +#define MAX_WIN_SIZE OSD_VIDWIN0XP_V0X +#define MAX_LINE_LENGTH (OSD_VIDWIN0OFST_V0LO << 5) + +/** + * _osd_dm6446_vid0_pingpong() - field inversion fix for DM6446 + * @sd - ptr to struct osd_state + * @field_inversion - inversion flag + * @fb_base_phys - frame buffer address + * @lconfig - ptr to layer config + * + * This routine implements a workaround for the field signal inversion silicon + * erratum described in Advisory 1.3.8 for the DM6446. The fb_base_phys and + * lconfig parameters apply to the vid0 window. This routine should be called + * whenever the vid0 layer configuration or start address is modified, or when + * the OSD field inversion setting is modified. + * Returns: 1 if the ping-pong buffers need to be toggled in the vsync isr, or + * 0 otherwise + */ +static int _osd_dm6446_vid0_pingpong(struct osd_state *sd, + int field_inversion, + unsigned long fb_base_phys, + const struct osd_layer_config *lconfig) +{ + struct osd_platform_data *pdata; + + pdata = (struct osd_platform_data *)sd->dev->platform_data; + if (pdata->field_inv_wa_enable) { + + if (!field_inversion || !lconfig->interlaced) { + osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); + osd_write(sd, fb_base_phys & ~0x1F, OSD_PPVWIN0ADR); + osd_modify(sd, OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, 0, + OSD_MISCCTL); + return 0; + } else { + unsigned miscctl = OSD_MISCCTL_PPRV; + + osd_write(sd, + (fb_base_phys & ~0x1F) - lconfig->line_length, + OSD_VIDWIN0ADR); + osd_write(sd, + (fb_base_phys & ~0x1F) + lconfig->line_length, + OSD_PPVWIN0ADR); + osd_modify(sd, + OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, miscctl, + OSD_MISCCTL); + + return 1; + } + } + + return 0; +} + +static void _osd_set_field_inversion(struct osd_state *sd, int enable) +{ + unsigned fsinv = 0; + + if (enable) + fsinv = OSD_MODE_FSINV; + + osd_modify(sd, OSD_MODE_FSINV, fsinv, OSD_MODE); +} + +static void _osd_set_blink_attribute(struct osd_state *sd, int enable, + enum osd_blink_interval blink) +{ + u32 osdatrmd = 0; + + if (enable) { + osdatrmd |= OSD_OSDATRMD_BLNK; + osdatrmd |= blink << OSD_OSDATRMD_BLNKINT_SHIFT; + } + /* caller must ensure that OSD1 is configured in attribute mode */ + osd_modify(sd, OSD_OSDATRMD_BLNKINT | OSD_OSDATRMD_BLNK, osdatrmd, + OSD_OSDATRMD); +} + +static void _osd_set_rom_clut(struct osd_state *sd, + enum osd_rom_clut rom_clut) +{ + if (rom_clut == ROM_CLUT0) + osd_clear(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL); + else + osd_set(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL); +} + +static void _osd_set_palette_map(struct osd_state *sd, + enum osd_win_layer osdwin, + unsigned char pixel_value, + unsigned char clut_index, + enum osd_pix_format pixfmt) +{ + static const int map_2bpp[] = { 0, 5, 10, 15 }; + static const int map_1bpp[] = { 0, 15 }; + int bmp_offset; + int bmp_shift; + int bmp_mask; + int bmp_reg; + + switch (pixfmt) { + case PIXFMT_1BPP: + bmp_reg = map_1bpp[pixel_value & 0x1]; + break; + case PIXFMT_2BPP: + bmp_reg = map_2bpp[pixel_value & 0x3]; + break; + case PIXFMT_4BPP: + bmp_reg = pixel_value & 0xf; + break; + default: + return; + } + + switch (osdwin) { + case OSDWIN_OSD0: + bmp_offset = OSD_W0BMP01 + (bmp_reg >> 1) * sizeof(u32); + break; + case OSDWIN_OSD1: + bmp_offset = OSD_W1BMP01 + (bmp_reg >> 1) * sizeof(u32); + break; + default: + return; + } + + if (bmp_reg & 1) { + bmp_shift = 8; + bmp_mask = 0xff << 8; + } else { + bmp_shift = 0; + bmp_mask = 0xff; + } + + osd_modify(sd, bmp_mask, clut_index << bmp_shift, bmp_offset); +} + +static void _osd_set_rec601_attenuation(struct osd_state *sd, + enum osd_win_layer osdwin, int enable) +{ + switch (osdwin) { + case OSDWIN_OSD0: + osd_modify(sd, OSD_OSDWIN0MD_ATN0E, + enable ? OSD_OSDWIN0MD_ATN0E : 0, + OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + osd_modify(sd, OSD_OSDWIN1MD_ATN1E, + enable ? OSD_OSDWIN1MD_ATN1E : 0, + OSD_OSDWIN1MD); + break; + } +} + +static void _osd_set_blending_factor(struct osd_state *sd, + enum osd_win_layer osdwin, + enum osd_blending_factor blend) +{ + switch (osdwin) { + case OSDWIN_OSD0: + osd_modify(sd, OSD_OSDWIN0MD_BLND0, + blend << OSD_OSDWIN0MD_BLND0_SHIFT, OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + osd_modify(sd, OSD_OSDWIN1MD_BLND1, + blend << OSD_OSDWIN1MD_BLND1_SHIFT, OSD_OSDWIN1MD); + break; + } +} + +static void _osd_enable_color_key(struct osd_state *sd, + enum osd_win_layer osdwin, + unsigned colorkey, + enum osd_pix_format pixfmt) +{ + switch (pixfmt) { + case PIXFMT_RGB565: + osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS, + OSD_TRANSPVAL); + break; + default: + break; + } + + switch (osdwin) { + case OSDWIN_OSD0: + osd_set(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + osd_set(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD); + break; + } +} + +static void _osd_disable_color_key(struct osd_state *sd, + enum osd_win_layer osdwin) +{ + switch (osdwin) { + case OSDWIN_OSD0: + osd_clear(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + osd_clear(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD); + break; + } +} + +static void _osd_set_osd_clut(struct osd_state *sd, + enum osd_win_layer osdwin, + enum osd_clut clut) +{ + u32 winmd = 0; + + switch (osdwin) { + case OSDWIN_OSD0: + if (clut == RAM_CLUT) + winmd |= OSD_OSDWIN0MD_CLUTS0; + osd_modify(sd, OSD_OSDWIN0MD_CLUTS0, winmd, OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + if (clut == RAM_CLUT) + winmd |= OSD_OSDWIN1MD_CLUTS1; + osd_modify(sd, OSD_OSDWIN1MD_CLUTS1, winmd, OSD_OSDWIN1MD); + break; + } +} + +static void _osd_set_zoom(struct osd_state *sd, enum osd_layer layer, + enum osd_zoom_factor h_zoom, + enum osd_zoom_factor v_zoom) +{ + u32 winmd = 0; + + switch (layer) { + case WIN_OSD0: + winmd |= (h_zoom << OSD_OSDWIN0MD_OHZ0_SHIFT); + winmd |= (v_zoom << OSD_OSDWIN0MD_OVZ0_SHIFT); + osd_modify(sd, OSD_OSDWIN0MD_OHZ0 | OSD_OSDWIN0MD_OVZ0, winmd, + OSD_OSDWIN0MD); + break; + case WIN_VID0: + winmd |= (h_zoom << OSD_VIDWINMD_VHZ0_SHIFT); + winmd |= (v_zoom << OSD_VIDWINMD_VVZ0_SHIFT); + osd_modify(sd, OSD_VIDWINMD_VHZ0 | OSD_VIDWINMD_VVZ0, winmd, + OSD_VIDWINMD); + break; + case WIN_OSD1: + winmd |= (h_zoom << OSD_OSDWIN1MD_OHZ1_SHIFT); + winmd |= (v_zoom << OSD_OSDWIN1MD_OVZ1_SHIFT); + osd_modify(sd, OSD_OSDWIN1MD_OHZ1 | OSD_OSDWIN1MD_OVZ1, winmd, + OSD_OSDWIN1MD); + break; + case WIN_VID1: + winmd |= (h_zoom << OSD_VIDWINMD_VHZ1_SHIFT); + winmd |= (v_zoom << OSD_VIDWINMD_VVZ1_SHIFT); + osd_modify(sd, OSD_VIDWINMD_VHZ1 | OSD_VIDWINMD_VVZ1, winmd, + OSD_VIDWINMD); + break; + } +} + +static void _osd_disable_layer(struct osd_state *sd, enum osd_layer layer) +{ + switch (layer) { + case WIN_OSD0: + osd_clear(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD); + break; + case WIN_VID0: + osd_clear(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD); + break; + case WIN_OSD1: + /* disable attribute mode as well as disabling the window */ + osd_clear(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1, + OSD_OSDWIN1MD); + break; + case WIN_VID1: + osd_clear(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD); + break; + } +} + +static void osd_disable_layer(struct osd_state *sd, enum osd_layer layer) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + if (!win->is_enabled) { + spin_unlock_irqrestore(&osd->lock, flags); + return; + } + win->is_enabled = 0; + + _osd_disable_layer(sd, layer); + + spin_unlock_irqrestore(&osd->lock, flags); +} + +static void _osd_enable_attribute_mode(struct osd_state *sd) +{ + /* enable attribute mode for OSD1 */ + osd_set(sd, OSD_OSDWIN1MD_OASW, OSD_OSDWIN1MD); +} + +static void _osd_enable_layer(struct osd_state *sd, enum osd_layer layer) +{ + switch (layer) { + case WIN_OSD0: + osd_set(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD); + break; + case WIN_VID0: + osd_set(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD); + break; + case WIN_OSD1: + /* enable OSD1 and disable attribute mode */ + osd_modify(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1, + OSD_OSDWIN1MD_OACT1, OSD_OSDWIN1MD); + break; + case WIN_VID1: + osd_set(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD); + break; + } +} + +static int osd_enable_layer(struct osd_state *sd, enum osd_layer layer, + int otherwin) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + struct osd_layer_config *cfg = &win->lconfig; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + /* + * use otherwin flag to know this is the other vid window + * in YUV420 mode, if is, skip this check + */ + if (!otherwin && (!win->is_allocated || + !win->fb_base_phys || + !cfg->line_length || + !cfg->xsize || + !cfg->ysize)) { + spin_unlock_irqrestore(&osd->lock, flags); + return -1; + } + + if (win->is_enabled) { + spin_unlock_irqrestore(&osd->lock, flags); + return 0; + } + win->is_enabled = 1; + + if (cfg->pixfmt != PIXFMT_OSD_ATTR) + _osd_enable_layer(sd, layer); + else { + _osd_enable_attribute_mode(sd); + _osd_set_blink_attribute(sd, osd->is_blinking, osd->blink); + } + + spin_unlock_irqrestore(&osd->lock, flags); + + return 0; +} + +static void _osd_start_layer(struct osd_state *sd, enum osd_layer layer, + unsigned long fb_base_phys, + unsigned long cbcr_ofst) +{ + switch (layer) { + case WIN_OSD0: + osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR); + break; + case WIN_VID0: + osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); + break; + case WIN_OSD1: + osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR); + break; + case WIN_VID1: + osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR); + break; + } +} + +static void osd_start_layer(struct osd_state *sd, enum osd_layer layer, + unsigned long fb_base_phys, + unsigned long cbcr_ofst) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + struct osd_layer_config *cfg = &win->lconfig; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + win->fb_base_phys = fb_base_phys & ~0x1F; + _osd_start_layer(sd, layer, fb_base_phys, cbcr_ofst); + + if (layer == WIN_VID0) { + osd->pingpong = + _osd_dm6446_vid0_pingpong(sd, osd->field_inversion, + win->fb_base_phys, + cfg); + } + + spin_unlock_irqrestore(&osd->lock, flags); +} + +static void osd_get_layer_config(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + *lconfig = win->lconfig; + + spin_unlock_irqrestore(&osd->lock, flags); +} + +/** + * try_layer_config() - Try a specific configuration for the layer + * @sd - ptr to struct osd_state + * @layer - layer to configure + * @lconfig - layer configuration to try + * + * If the requested lconfig is completely rejected and the value of lconfig on + * exit is the current lconfig, then try_layer_config() returns 1. Otherwise, + * try_layer_config() returns 0. A return value of 0 does not necessarily mean + * that the value of lconfig on exit is identical to the value of lconfig on + * entry, but merely that it represents a change from the current lconfig. + */ +static int try_layer_config(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + int bad_config; + + /* verify that the pixel format is compatible with the layer */ + switch (lconfig->pixfmt) { + case PIXFMT_1BPP: + case PIXFMT_2BPP: + case PIXFMT_4BPP: + case PIXFMT_8BPP: + case PIXFMT_RGB565: + bad_config = !is_osd_win(layer); + break; + case PIXFMT_YCbCrI: + case PIXFMT_YCrCbI: + bad_config = !is_vid_win(layer); + break; + case PIXFMT_RGB888: + bad_config = !is_vid_win(layer); + break; + case PIXFMT_NV12: + bad_config = 1; + break; + case PIXFMT_OSD_ATTR: + bad_config = (layer != WIN_OSD1); + break; + default: + bad_config = 1; + break; + } + if (bad_config) { + /* + * The requested pixel format is incompatible with the layer, + * so keep the current layer configuration. + */ + *lconfig = win->lconfig; + return bad_config; + } + + /* DM6446: */ + /* only one OSD window at a time can use RGB pixel formats */ + if (is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) { + enum osd_pix_format pixfmt; + if (layer == WIN_OSD0) + pixfmt = osd->win[WIN_OSD1].lconfig.pixfmt; + else + pixfmt = osd->win[WIN_OSD0].lconfig.pixfmt; + + if (is_rgb_pixfmt(pixfmt)) { + /* + * The other OSD window is already configured for an + * RGB, so keep the current layer configuration. + */ + *lconfig = win->lconfig; + return 1; + } + } + + /* DM6446: only one video window at a time can use RGB888 */ + if (is_vid_win(layer) && lconfig->pixfmt == PIXFMT_RGB888) { + enum osd_pix_format pixfmt; + + if (layer == WIN_VID0) + pixfmt = osd->win[WIN_VID1].lconfig.pixfmt; + else + pixfmt = osd->win[WIN_VID0].lconfig.pixfmt; + + if (pixfmt == PIXFMT_RGB888) { + /* + * The other video window is already configured for + * RGB888, so keep the current layer configuration. + */ + *lconfig = win->lconfig; + return 1; + } + } + + /* window dimensions must be non-zero */ + if (!lconfig->line_length || !lconfig->xsize || !lconfig->ysize) { + *lconfig = win->lconfig; + return 1; + } + + /* round line_length up to a multiple of 32 */ + lconfig->line_length = ((lconfig->line_length + 31) / 32) * 32; + lconfig->line_length = + min(lconfig->line_length, (unsigned)MAX_LINE_LENGTH); + lconfig->xsize = min(lconfig->xsize, (unsigned)MAX_WIN_SIZE); + lconfig->ysize = min(lconfig->ysize, (unsigned)MAX_WIN_SIZE); + lconfig->xpos = min(lconfig->xpos, (unsigned)MAX_WIN_SIZE); + lconfig->ypos = min(lconfig->ypos, (unsigned)MAX_WIN_SIZE); + lconfig->interlaced = (lconfig->interlaced != 0); + if (lconfig->interlaced) { + /* ysize and ypos must be even for interlaced displays */ + lconfig->ysize &= ~1; + lconfig->ypos &= ~1; + } + + return 0; +} + +static void _osd_disable_vid_rgb888(struct osd_state *sd) +{ + /* + * The DM6446 supports RGB888 pixel format in a single video window. + * This routine disables RGB888 pixel format for both video windows. + * The caller must ensure that neither video window is currently + * configured for RGB888 pixel format. + */ + osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL); +} + +static void _osd_enable_vid_rgb888(struct osd_state *sd, + enum osd_layer layer) +{ + /* + * The DM6446 supports RGB888 pixel format in a single video window. + * This routine enables RGB888 pixel format for the specified video + * window. The caller must ensure that the other video window is not + * currently configured for RGB888 pixel format, as this routine will + * disable RGB888 pixel format for the other window. + */ + if (layer == WIN_VID0) { + osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL_RGBEN, OSD_MISCCTL); + } else if (layer == WIN_VID1) { + osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL); + } +} + +static void _osd_set_cbcr_order(struct osd_state *sd, + enum osd_pix_format pixfmt) +{ + /* + * The caller must ensure that all windows using YC pixfmt use the same + * Cb/Cr order. + */ + if (pixfmt == PIXFMT_YCbCrI) + osd_clear(sd, OSD_MODE_CS, OSD_MODE); + else if (pixfmt == PIXFMT_YCrCbI) + osd_set(sd, OSD_MODE_CS, OSD_MODE); +} + +static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, + const struct osd_layer_config *lconfig) +{ + u32 winmd = 0, winmd_mask = 0, bmw = 0; + + _osd_set_cbcr_order(sd, lconfig->pixfmt); + + switch (layer) { + case WIN_OSD0: + winmd_mask |= OSD_OSDWIN0MD_RGB0E; + if (lconfig->pixfmt == PIXFMT_RGB565) + winmd |= OSD_OSDWIN0MD_RGB0E; + + winmd_mask |= OSD_OSDWIN0MD_BMW0 | OSD_OSDWIN0MD_OFF0; + + switch (lconfig->pixfmt) { + case PIXFMT_1BPP: + bmw = 0; + break; + case PIXFMT_2BPP: + bmw = 1; + break; + case PIXFMT_4BPP: + bmw = 2; + break; + case PIXFMT_8BPP: + bmw = 3; + break; + default: + break; + } + winmd |= (bmw << OSD_OSDWIN0MD_BMW0_SHIFT); + + if (lconfig->interlaced) + winmd |= OSD_OSDWIN0MD_OFF0; + + osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN0MD); + osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN0OFST); + osd_write(sd, lconfig->xpos, OSD_OSDWIN0XP); + osd_write(sd, lconfig->xsize, OSD_OSDWIN0XL); + if (lconfig->interlaced) { + osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN0YP); + osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN0YL); + } else { + osd_write(sd, lconfig->ypos, OSD_OSDWIN0YP); + osd_write(sd, lconfig->ysize, OSD_OSDWIN0YL); + } + break; + case WIN_VID0: + winmd_mask |= OSD_VIDWINMD_VFF0; + if (lconfig->interlaced) + winmd |= OSD_VIDWINMD_VFF0; + + osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD); + osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN0OFST); + osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP); + osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL); + /* + * For YUV420P format the register contents are + * duplicated in both VID registers + */ + if (lconfig->interlaced) { + osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN0YP); + osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN0YL); + } else { + osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP); + osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL); + } + break; + case WIN_OSD1: + /* + * The caller must ensure that OSD1 is disabled prior to + * switching from a normal mode to attribute mode or from + * attribute mode to a normal mode. + */ + if (lconfig->pixfmt == PIXFMT_OSD_ATTR) { + winmd_mask |= + OSD_OSDWIN1MD_ATN1E | OSD_OSDWIN1MD_RGB1E | + OSD_OSDWIN1MD_CLUTS1 | + OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1; + } else { + winmd_mask |= OSD_OSDWIN1MD_RGB1E; + if (lconfig->pixfmt == PIXFMT_RGB565) + winmd |= OSD_OSDWIN1MD_RGB1E; + + winmd_mask |= OSD_OSDWIN1MD_BMW1; + switch (lconfig->pixfmt) { + case PIXFMT_1BPP: + bmw = 0; + break; + case PIXFMT_2BPP: + bmw = 1; + break; + case PIXFMT_4BPP: + bmw = 2; + break; + case PIXFMT_8BPP: + bmw = 3; + break; + default: + break; + } + winmd |= (bmw << OSD_OSDWIN1MD_BMW1_SHIFT); + } + + winmd_mask |= OSD_OSDWIN1MD_OFF1; + if (lconfig->interlaced) + winmd |= OSD_OSDWIN1MD_OFF1; + + osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN1MD); + osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN1OFST); + osd_write(sd, lconfig->xpos, OSD_OSDWIN1XP); + osd_write(sd, lconfig->xsize, OSD_OSDWIN1XL); + if (lconfig->interlaced) { + osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN1YP); + osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN1YL); + } else { + osd_write(sd, lconfig->ypos, OSD_OSDWIN1YP); + osd_write(sd, lconfig->ysize, OSD_OSDWIN1YL); + } + break; + case WIN_VID1: + winmd_mask |= OSD_VIDWINMD_VFF1; + if (lconfig->interlaced) + winmd |= OSD_VIDWINMD_VFF1; + + osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD); + osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN1OFST); + osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP); + osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL); + /* + * For YUV420P format the register contents are + * duplicated in both VID registers + */ + osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D, + OSD_MISCCTL); + + if (lconfig->interlaced) { + osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN1YP); + osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN1YL); + } else { + osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP); + osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL); + } + break; + } +} + +static int osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + struct osd_layer_config *cfg = &win->lconfig; + unsigned long flags; + int reject_config; + + spin_lock_irqsave(&osd->lock, flags); + + reject_config = try_layer_config(sd, layer, lconfig); + if (reject_config) { + spin_unlock_irqrestore(&osd->lock, flags); + return reject_config; + } + + /* update the current Cb/Cr order */ + if (is_yc_pixfmt(lconfig->pixfmt)) + osd->yc_pixfmt = lconfig->pixfmt; + + /* + * If we are switching OSD1 from normal mode to attribute mode or from + * attribute mode to normal mode, then we must disable the window. + */ + if (layer == WIN_OSD1) { + if (((lconfig->pixfmt == PIXFMT_OSD_ATTR) && + (cfg->pixfmt != PIXFMT_OSD_ATTR)) || + ((lconfig->pixfmt != PIXFMT_OSD_ATTR) && + (cfg->pixfmt == PIXFMT_OSD_ATTR))) { + win->is_enabled = 0; + _osd_disable_layer(sd, layer); + } + } + + _osd_set_layer_config(sd, layer, lconfig); + + if (layer == WIN_OSD1) { + struct osd_osdwin_state *osdwin_state = + &osd->osdwin[OSDWIN_OSD1]; + + if ((lconfig->pixfmt != PIXFMT_OSD_ATTR) && + (cfg->pixfmt == PIXFMT_OSD_ATTR)) { + /* + * We just switched OSD1 from attribute mode to normal + * mode, so we must initialize the CLUT select, the + * blend factor, transparency colorkey enable, and + * attenuation enable (DM6446 only) bits in the + * OSDWIN1MD register. + */ + _osd_set_osd_clut(sd, OSDWIN_OSD1, + osdwin_state->clut); + _osd_set_blending_factor(sd, OSDWIN_OSD1, + osdwin_state->blend); + if (osdwin_state->colorkey_blending) { + _osd_enable_color_key(sd, OSDWIN_OSD1, + osdwin_state-> + colorkey, + lconfig->pixfmt); + } else + _osd_disable_color_key(sd, OSDWIN_OSD1); + _osd_set_rec601_attenuation(sd, OSDWIN_OSD1, + osdwin_state-> + rec601_attenuation); + } else if ((lconfig->pixfmt == PIXFMT_OSD_ATTR) && + (cfg->pixfmt != PIXFMT_OSD_ATTR)) { + /* + * We just switched OSD1 from normal mode to attribute + * mode, so we must initialize the blink enable and + * blink interval bits in the OSDATRMD register. + */ + _osd_set_blink_attribute(sd, osd->is_blinking, + osd->blink); + } + } + + /* + * If we just switched to a 1-, 2-, or 4-bits-per-pixel bitmap format + * then configure a default palette map. + */ + if ((lconfig->pixfmt != cfg->pixfmt) && + ((lconfig->pixfmt == PIXFMT_1BPP) || + (lconfig->pixfmt == PIXFMT_2BPP) || + (lconfig->pixfmt == PIXFMT_4BPP))) { + enum osd_win_layer osdwin = + ((layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1); + struct osd_osdwin_state *osdwin_state = + &osd->osdwin[osdwin]; + unsigned char clut_index; + unsigned char clut_entries = 0; + + switch (lconfig->pixfmt) { + case PIXFMT_1BPP: + clut_entries = 2; + break; + case PIXFMT_2BPP: + clut_entries = 4; + break; + case PIXFMT_4BPP: + clut_entries = 16; + break; + default: + break; + } + /* + * The default palette map maps the pixel value to the clut + * index, i.e. pixel value 0 maps to clut entry 0, pixel value + * 1 maps to clut entry 1, etc. + */ + for (clut_index = 0; clut_index < 16; clut_index++) { + osdwin_state->palette_map[clut_index] = clut_index; + if (clut_index < clut_entries) { + _osd_set_palette_map(sd, osdwin, clut_index, + clut_index, + lconfig->pixfmt); + } + } + } + + *cfg = *lconfig; + /* DM6446: configure the RGB888 enable and window selection */ + if (osd->win[WIN_VID0].lconfig.pixfmt == PIXFMT_RGB888) + _osd_enable_vid_rgb888(sd, WIN_VID0); + else if (osd->win[WIN_VID1].lconfig.pixfmt == PIXFMT_RGB888) + _osd_enable_vid_rgb888(sd, WIN_VID1); + else + _osd_disable_vid_rgb888(sd); + + if (layer == WIN_VID0) { + osd->pingpong = + _osd_dm6446_vid0_pingpong(sd, osd->field_inversion, + win->fb_base_phys, + cfg); + } + + spin_unlock_irqrestore(&osd->lock, flags); + + return 0; +} + +static void osd_init_layer(struct osd_state *sd, enum osd_layer layer) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + enum osd_win_layer osdwin; + struct osd_osdwin_state *osdwin_state; + struct osd_layer_config *cfg = &win->lconfig; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + win->is_enabled = 0; + _osd_disable_layer(sd, layer); + + win->h_zoom = ZOOM_X1; + win->v_zoom = ZOOM_X1; + _osd_set_zoom(sd, layer, win->h_zoom, win->v_zoom); + + win->fb_base_phys = 0; + _osd_start_layer(sd, layer, win->fb_base_phys, 0); + + cfg->line_length = 0; + cfg->xsize = 0; + cfg->ysize = 0; + cfg->xpos = 0; + cfg->ypos = 0; + cfg->interlaced = 0; + switch (layer) { + case WIN_OSD0: + case WIN_OSD1: + osdwin = (layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1; + osdwin_state = &osd->osdwin[osdwin]; + /* + * Other code relies on the fact that OSD windows default to a + * bitmap pixel format when they are deallocated, so don't + * change this default pixel format. + */ + cfg->pixfmt = PIXFMT_8BPP; + _osd_set_layer_config(sd, layer, cfg); + osdwin_state->clut = RAM_CLUT; + _osd_set_osd_clut(sd, osdwin, osdwin_state->clut); + osdwin_state->colorkey_blending = 0; + _osd_disable_color_key(sd, osdwin); + osdwin_state->blend = OSD_8_VID_0; + _osd_set_blending_factor(sd, osdwin, osdwin_state->blend); + osdwin_state->rec601_attenuation = 0; + _osd_set_rec601_attenuation(sd, osdwin, + osdwin_state-> + rec601_attenuation); + if (osdwin == OSDWIN_OSD1) { + osd->is_blinking = 0; + osd->blink = BLINK_X1; + } + break; + case WIN_VID0: + case WIN_VID1: + cfg->pixfmt = osd->yc_pixfmt; + _osd_set_layer_config(sd, layer, cfg); + break; + } + + spin_unlock_irqrestore(&osd->lock, flags); +} + +static void osd_release_layer(struct osd_state *sd, enum osd_layer layer) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + if (!win->is_allocated) { + spin_unlock_irqrestore(&osd->lock, flags); + return; + } + + spin_unlock_irqrestore(&osd->lock, flags); + osd_init_layer(sd, layer); + spin_lock_irqsave(&osd->lock, flags); + + win->is_allocated = 0; + + spin_unlock_irqrestore(&osd->lock, flags); +} + +static int osd_request_layer(struct osd_state *sd, enum osd_layer layer) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + if (win->is_allocated) { + spin_unlock_irqrestore(&osd->lock, flags); + return -1; + } + win->is_allocated = 1; + + spin_unlock_irqrestore(&osd->lock, flags); + + return 0; +} + +static void _osd_init(struct osd_state *sd) +{ + osd_write(sd, 0, OSD_MODE); + osd_write(sd, 0, OSD_VIDWINMD); + osd_write(sd, 0, OSD_OSDWIN0MD); + osd_write(sd, 0, OSD_OSDWIN1MD); + osd_write(sd, 0, OSD_RECTCUR); + osd_write(sd, 0, OSD_MISCCTL); +} + +static void osd_set_left_margin(struct osd_state *sd, u32 val) +{ + osd_write(sd, val, OSD_BASEPX); +} + +static void osd_set_top_margin(struct osd_state *sd, u32 val) +{ + osd_write(sd, val, OSD_BASEPY); +} + +static int osd_initialize(struct osd_state *osd) +{ + if (osd == NULL) + return -ENODEV; + _osd_init(osd); + + /* set default Cb/Cr order */ + osd->yc_pixfmt = PIXFMT_YCbCrI; + + _osd_set_field_inversion(osd, osd->field_inversion); + _osd_set_rom_clut(osd, osd->rom_clut); + + osd_init_layer(osd, WIN_OSD0); + osd_init_layer(osd, WIN_VID0); + osd_init_layer(osd, WIN_OSD1); + osd_init_layer(osd, WIN_VID1); + + return 0; +} + +static const struct vpbe_osd_ops osd_ops = { + .initialize = osd_initialize, + .request_layer = osd_request_layer, + .release_layer = osd_release_layer, + .enable_layer = osd_enable_layer, + .disable_layer = osd_disable_layer, + .set_layer_config = osd_set_layer_config, + .get_layer_config = osd_get_layer_config, + .start_layer = osd_start_layer, + .set_left_margin = osd_set_left_margin, + .set_top_margin = osd_set_top_margin, +}; + +static int osd_probe(struct platform_device *pdev) +{ + struct osd_platform_data *pdata; + struct osd_state *osd; + struct resource *res; + int ret = 0; + + osd = kzalloc(sizeof(struct osd_state), GFP_KERNEL); + if (osd == NULL) + return -ENOMEM; + + osd->dev = &pdev->dev; + pdata = (struct osd_platform_data *)pdev->dev.platform_data; + osd->vpbe_type = (enum vpbe_version)pdata->vpbe_type; + if (NULL == pdev->dev.platform_data) { + dev_err(osd->dev, "No platform data defined for OSD" + " sub device\n"); + ret = -ENOENT; + goto free_mem; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(osd->dev, "Unable to get OSD register address map\n"); + ret = -ENODEV; + goto free_mem; + } + osd->osd_base_phys = res->start; + osd->osd_size = res->end - res->start + 1; + if (!request_mem_region(osd->osd_base_phys, osd->osd_size, + MODULE_NAME)) { + dev_err(osd->dev, "Unable to reserve OSD MMIO region\n"); + ret = -ENODEV; + goto free_mem; + } + osd->osd_base = (unsigned long)ioremap_nocache(res->start, + osd->osd_size); + if (!osd->osd_base) { + dev_err(osd->dev, "Unable to map the OSD region\n"); + ret = -ENODEV; + goto release_mem_region; + } + spin_lock_init(&osd->lock); + osd->ops = osd_ops; + platform_set_drvdata(pdev, osd); + dev_notice(osd->dev, "OSD sub device probe success\n"); + return ret; + +release_mem_region: + release_mem_region(osd->osd_base_phys, osd->osd_size); +free_mem: + kfree(osd); + return ret; +} + +static int osd_remove(struct platform_device *pdev) +{ + struct osd_state *osd = platform_get_drvdata(pdev); + + iounmap((void *)osd->osd_base); + release_mem_region(osd->osd_base_phys, osd->osd_size); + kfree(osd); + return 0; +} + +static struct platform_driver osd_driver = { + .probe = osd_probe, + .remove = osd_remove, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + }, +}; + +static int osd_init(void) +{ + if (platform_driver_register(&osd_driver)) { + printk(KERN_ERR "Unable to register davinci osd driver\n"); + return -ENODEV; + } + + return 0; +} + +static void osd_exit(void) +{ + platform_driver_unregister(&osd_driver); +} + +module_init(osd_init); +module_exit(osd_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("DaVinci OSD Manager Driver"); +MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/media/video/davinci/vpbe_osd_regs.h b/drivers/media/video/davinci/vpbe_osd_regs.h new file mode 100644 index 0000000000000000000000000000000000000000..584520f3af608165d86c6bff4ecc32ac06d23f77 --- /dev/null +++ b/drivers/media/video/davinci/vpbe_osd_regs.h @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2006-2010 Texas Instruments Inc + * + * 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 version 2. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _VPBE_OSD_REGS_H +#define _VPBE_OSD_REGS_H + +/* VPBE Global Registers */ +#define VPBE_PID 0x0 +#define VPBE_PCR 0x4 + +/* VPSS CLock Registers */ +#define VPSSCLK_PID 0x00 +#define VPSSCLK_CLKCTRL 0x04 + +/* VPSS Buffer Logic Registers */ +#define VPSSBL_PID 0x00 +#define VPSSBL_PCR 0x04 +#define VPSSBL_BCR 0x08 +#define VPSSBL_INTSTAT 0x0C +#define VPSSBL_INTSEL 0x10 +#define VPSSBL_EVTSEL 0x14 +#define VPSSBL_MEMCTRL 0x18 +#define VPSSBL_CCDCMUX 0x1C + +/* DM365 ISP5 system configuration */ +#define ISP5_PID 0x0 +#define ISP5_PCCR 0x4 +#define ISP5_BCR 0x8 +#define ISP5_INTSTAT 0xC +#define ISP5_INTSEL1 0x10 +#define ISP5_INTSEL2 0x14 +#define ISP5_INTSEL3 0x18 +#define ISP5_EVTSEL 0x1c +#define ISP5_CCDCMUX 0x20 + +/* VPBE On-Screen Display Subsystem Registers (OSD) */ +#define OSD_MODE 0x00 +#define OSD_VIDWINMD 0x04 +#define OSD_OSDWIN0MD 0x08 +#define OSD_OSDWIN1MD 0x0C +#define OSD_OSDATRMD 0x0C +#define OSD_RECTCUR 0x10 +#define OSD_VIDWIN0OFST 0x18 +#define OSD_VIDWIN1OFST 0x1C +#define OSD_OSDWIN0OFST 0x20 +#define OSD_OSDWIN1OFST 0x24 +#define OSD_VIDWINADH 0x28 +#define OSD_VIDWIN0ADL 0x2C +#define OSD_VIDWIN0ADR 0x2C +#define OSD_VIDWIN1ADL 0x30 +#define OSD_VIDWIN1ADR 0x30 +#define OSD_OSDWINADH 0x34 +#define OSD_OSDWIN0ADL 0x38 +#define OSD_OSDWIN0ADR 0x38 +#define OSD_OSDWIN1ADL 0x3C +#define OSD_OSDWIN1ADR 0x3C +#define OSD_BASEPX 0x40 +#define OSD_BASEPY 0x44 +#define OSD_VIDWIN0XP 0x48 +#define OSD_VIDWIN0YP 0x4C +#define OSD_VIDWIN0XL 0x50 +#define OSD_VIDWIN0YL 0x54 +#define OSD_VIDWIN1XP 0x58 +#define OSD_VIDWIN1YP 0x5C +#define OSD_VIDWIN1XL 0x60 +#define OSD_VIDWIN1YL 0x64 +#define OSD_OSDWIN0XP 0x68 +#define OSD_OSDWIN0YP 0x6C +#define OSD_OSDWIN0XL 0x70 +#define OSD_OSDWIN0YL 0x74 +#define OSD_OSDWIN1XP 0x78 +#define OSD_OSDWIN1YP 0x7C +#define OSD_OSDWIN1XL 0x80 +#define OSD_OSDWIN1YL 0x84 +#define OSD_CURXP 0x88 +#define OSD_CURYP 0x8C +#define OSD_CURXL 0x90 +#define OSD_CURYL 0x94 +#define OSD_W0BMP01 0xA0 +#define OSD_W0BMP23 0xA4 +#define OSD_W0BMP45 0xA8 +#define OSD_W0BMP67 0xAC +#define OSD_W0BMP89 0xB0 +#define OSD_W0BMPAB 0xB4 +#define OSD_W0BMPCD 0xB8 +#define OSD_W0BMPEF 0xBC +#define OSD_W1BMP01 0xC0 +#define OSD_W1BMP23 0xC4 +#define OSD_W1BMP45 0xC8 +#define OSD_W1BMP67 0xCC +#define OSD_W1BMP89 0xD0 +#define OSD_W1BMPAB 0xD4 +#define OSD_W1BMPCD 0xD8 +#define OSD_W1BMPEF 0xDC +#define OSD_VBNDRY 0xE0 +#define OSD_EXTMODE 0xE4 +#define OSD_MISCCTL 0xE8 +#define OSD_CLUTRAMYCB 0xEC +#define OSD_CLUTRAMCR 0xF0 +#define OSD_TRANSPVAL 0xF4 +#define OSD_TRANSPVALL 0xF4 +#define OSD_TRANSPVALU 0xF8 +#define OSD_TRANSPBMPIDX 0xFC +#define OSD_PPVWIN0ADR 0xFC + +/* bit definitions */ +#define VPBE_PCR_VENC_DIV (1 << 1) +#define VPBE_PCR_CLK_OFF (1 << 0) + +#define VPSSBL_INTSTAT_HSSIINT (1 << 14) +#define VPSSBL_INTSTAT_CFALDINT (1 << 13) +#define VPSSBL_INTSTAT_IPIPE_INT5 (1 << 12) +#define VPSSBL_INTSTAT_IPIPE_INT4 (1 << 11) +#define VPSSBL_INTSTAT_IPIPE_INT3 (1 << 10) +#define VPSSBL_INTSTAT_IPIPE_INT2 (1 << 9) +#define VPSSBL_INTSTAT_IPIPE_INT1 (1 << 8) +#define VPSSBL_INTSTAT_IPIPE_INT0 (1 << 7) +#define VPSSBL_INTSTAT_IPIPEIFINT (1 << 6) +#define VPSSBL_INTSTAT_OSDINT (1 << 5) +#define VPSSBL_INTSTAT_VENCINT (1 << 4) +#define VPSSBL_INTSTAT_H3AINT (1 << 3) +#define VPSSBL_INTSTAT_CCDC_VDINT2 (1 << 2) +#define VPSSBL_INTSTAT_CCDC_VDINT1 (1 << 1) +#define VPSSBL_INTSTAT_CCDC_VDINT0 (1 << 0) + +/* DM365 ISP5 bit definitions */ +#define ISP5_INTSTAT_VENCINT (1 << 21) +#define ISP5_INTSTAT_OSDINT (1 << 20) + +/* VMOD TVTYP options for HDMD=0 */ +#define SDTV_NTSC 0 +#define SDTV_PAL 1 +/* VMOD TVTYP options for HDMD=1 */ +#define HDTV_525P 0 +#define HDTV_625P 1 +#define HDTV_1080I 2 +#define HDTV_720P 3 + +#define OSD_MODE_CS (1 << 15) +#define OSD_MODE_OVRSZ (1 << 14) +#define OSD_MODE_OHRSZ (1 << 13) +#define OSD_MODE_EF (1 << 12) +#define OSD_MODE_VVRSZ (1 << 11) +#define OSD_MODE_VHRSZ (1 << 10) +#define OSD_MODE_FSINV (1 << 9) +#define OSD_MODE_BCLUT (1 << 8) +#define OSD_MODE_CABG_SHIFT 0 +#define OSD_MODE_CABG (0xff << 0) + +#define OSD_VIDWINMD_VFINV (1 << 15) +#define OSD_VIDWINMD_V1EFC (1 << 14) +#define OSD_VIDWINMD_VHZ1_SHIFT 12 +#define OSD_VIDWINMD_VHZ1 (3 << 12) +#define OSD_VIDWINMD_VVZ1_SHIFT 10 +#define OSD_VIDWINMD_VVZ1 (3 << 10) +#define OSD_VIDWINMD_VFF1 (1 << 9) +#define OSD_VIDWINMD_ACT1 (1 << 8) +#define OSD_VIDWINMD_V0EFC (1 << 6) +#define OSD_VIDWINMD_VHZ0_SHIFT 4 +#define OSD_VIDWINMD_VHZ0 (3 << 4) +#define OSD_VIDWINMD_VVZ0_SHIFT 2 +#define OSD_VIDWINMD_VVZ0 (3 << 2) +#define OSD_VIDWINMD_VFF0 (1 << 1) +#define OSD_VIDWINMD_ACT0 (1 << 0) + +#define OSD_OSDWIN0MD_ATN0E (1 << 14) +#define OSD_OSDWIN0MD_RGB0E (1 << 13) +#define OSD_OSDWIN0MD_BMP0MD_SHIFT 13 +#define OSD_OSDWIN0MD_BMP0MD (3 << 13) +#define OSD_OSDWIN0MD_CLUTS0 (1 << 12) +#define OSD_OSDWIN0MD_OHZ0_SHIFT 10 +#define OSD_OSDWIN0MD_OHZ0 (3 << 10) +#define OSD_OSDWIN0MD_OVZ0_SHIFT 8 +#define OSD_OSDWIN0MD_OVZ0 (3 << 8) +#define OSD_OSDWIN0MD_BMW0_SHIFT 6 +#define OSD_OSDWIN0MD_BMW0 (3 << 6) +#define OSD_OSDWIN0MD_BLND0_SHIFT 3 +#define OSD_OSDWIN0MD_BLND0 (7 << 3) +#define OSD_OSDWIN0MD_TE0 (1 << 2) +#define OSD_OSDWIN0MD_OFF0 (1 << 1) +#define OSD_OSDWIN0MD_OACT0 (1 << 0) + +#define OSD_OSDWIN1MD_OASW (1 << 15) +#define OSD_OSDWIN1MD_ATN1E (1 << 14) +#define OSD_OSDWIN1MD_RGB1E (1 << 13) +#define OSD_OSDWIN1MD_BMP1MD_SHIFT 13 +#define OSD_OSDWIN1MD_BMP1MD (3 << 13) +#define OSD_OSDWIN1MD_CLUTS1 (1 << 12) +#define OSD_OSDWIN1MD_OHZ1_SHIFT 10 +#define OSD_OSDWIN1MD_OHZ1 (3 << 10) +#define OSD_OSDWIN1MD_OVZ1_SHIFT 8 +#define OSD_OSDWIN1MD_OVZ1 (3 << 8) +#define OSD_OSDWIN1MD_BMW1_SHIFT 6 +#define OSD_OSDWIN1MD_BMW1 (3 << 6) +#define OSD_OSDWIN1MD_BLND1_SHIFT 3 +#define OSD_OSDWIN1MD_BLND1 (7 << 3) +#define OSD_OSDWIN1MD_TE1 (1 << 2) +#define OSD_OSDWIN1MD_OFF1 (1 << 1) +#define OSD_OSDWIN1MD_OACT1 (1 << 0) + +#define OSD_OSDATRMD_OASW (1 << 15) +#define OSD_OSDATRMD_OHZA_SHIFT 10 +#define OSD_OSDATRMD_OHZA (3 << 10) +#define OSD_OSDATRMD_OVZA_SHIFT 8 +#define OSD_OSDATRMD_OVZA (3 << 8) +#define OSD_OSDATRMD_BLNKINT_SHIFT 6 +#define OSD_OSDATRMD_BLNKINT (3 << 6) +#define OSD_OSDATRMD_OFFA (1 << 1) +#define OSD_OSDATRMD_BLNK (1 << 0) + +#define OSD_RECTCUR_RCAD_SHIFT 8 +#define OSD_RECTCUR_RCAD (0xff << 8) +#define OSD_RECTCUR_CLUTSR (1 << 7) +#define OSD_RECTCUR_RCHW_SHIFT 4 +#define OSD_RECTCUR_RCHW (7 << 4) +#define OSD_RECTCUR_RCVW_SHIFT 1 +#define OSD_RECTCUR_RCVW (7 << 1) +#define OSD_RECTCUR_RCACT (1 << 0) + +#define OSD_VIDWIN0OFST_V0LO (0x1ff << 0) + +#define OSD_VIDWIN1OFST_V1LO (0x1ff << 0) + +#define OSD_OSDWIN0OFST_O0LO (0x1ff << 0) + +#define OSD_OSDWIN1OFST_O1LO (0x1ff << 0) + +#define OSD_WINOFST_AH_SHIFT 9 + +#define OSD_VIDWIN0OFST_V0AH (0xf << 9) +#define OSD_VIDWIN1OFST_V1AH (0xf << 9) +#define OSD_OSDWIN0OFST_O0AH (0xf << 9) +#define OSD_OSDWIN1OFST_O1AH (0xf << 9) + +#define OSD_VIDWINADH_V1AH_SHIFT 8 +#define OSD_VIDWINADH_V1AH (0x7f << 8) +#define OSD_VIDWINADH_V0AH_SHIFT 0 +#define OSD_VIDWINADH_V0AH (0x7f << 0) + +#define OSD_VIDWIN0ADL_V0AL (0xffff << 0) + +#define OSD_VIDWIN1ADL_V1AL (0xffff << 0) + +#define OSD_OSDWINADH_O1AH_SHIFT 8 +#define OSD_OSDWINADH_O1AH (0x7f << 8) +#define OSD_OSDWINADH_O0AH_SHIFT 0 +#define OSD_OSDWINADH_O0AH (0x7f << 0) + +#define OSD_OSDWIN0ADL_O0AL (0xffff << 0) + +#define OSD_OSDWIN1ADL_O1AL (0xffff << 0) + +#define OSD_BASEPX_BPX (0x3ff << 0) + +#define OSD_BASEPY_BPY (0x1ff << 0) + +#define OSD_VIDWIN0XP_V0X (0x7ff << 0) + +#define OSD_VIDWIN0YP_V0Y (0x7ff << 0) + +#define OSD_VIDWIN0XL_V0W (0x7ff << 0) + +#define OSD_VIDWIN0YL_V0H (0x7ff << 0) + +#define OSD_VIDWIN1XP_V1X (0x7ff << 0) + +#define OSD_VIDWIN1YP_V1Y (0x7ff << 0) + +#define OSD_VIDWIN1XL_V1W (0x7ff << 0) + +#define OSD_VIDWIN1YL_V1H (0x7ff << 0) + +#define OSD_OSDWIN0XP_W0X (0x7ff << 0) + +#define OSD_OSDWIN0YP_W0Y (0x7ff << 0) + +#define OSD_OSDWIN0XL_W0W (0x7ff << 0) + +#define OSD_OSDWIN0YL_W0H (0x7ff << 0) + +#define OSD_OSDWIN1XP_W1X (0x7ff << 0) + +#define OSD_OSDWIN1YP_W1Y (0x7ff << 0) + +#define OSD_OSDWIN1XL_W1W (0x7ff << 0) + +#define OSD_OSDWIN1YL_W1H (0x7ff << 0) + +#define OSD_CURXP_RCSX (0x7ff << 0) + +#define OSD_CURYP_RCSY (0x7ff << 0) + +#define OSD_CURXL_RCSW (0x7ff << 0) + +#define OSD_CURYL_RCSH (0x7ff << 0) + +#define OSD_EXTMODE_EXPMDSEL (1 << 15) +#define OSD_EXTMODE_SCRNHEXP_SHIFT 13 +#define OSD_EXTMODE_SCRNHEXP (3 << 13) +#define OSD_EXTMODE_SCRNVEXP (1 << 12) +#define OSD_EXTMODE_OSD1BLDCHR (1 << 11) +#define OSD_EXTMODE_OSD0BLDCHR (1 << 10) +#define OSD_EXTMODE_ATNOSD1EN (1 << 9) +#define OSD_EXTMODE_ATNOSD0EN (1 << 8) +#define OSD_EXTMODE_OSDHRSZ15 (1 << 7) +#define OSD_EXTMODE_VIDHRSZ15 (1 << 6) +#define OSD_EXTMODE_ZMFILV1HEN (1 << 5) +#define OSD_EXTMODE_ZMFILV1VEN (1 << 4) +#define OSD_EXTMODE_ZMFILV0HEN (1 << 3) +#define OSD_EXTMODE_ZMFILV0VEN (1 << 2) +#define OSD_EXTMODE_EXPFILHEN (1 << 1) +#define OSD_EXTMODE_EXPFILVEN (1 << 0) + +#define OSD_MISCCTL_BLDSEL (1 << 15) +#define OSD_MISCCTL_S420D (1 << 14) +#define OSD_MISCCTL_BMAPT (1 << 13) +#define OSD_MISCCTL_DM365M (1 << 12) +#define OSD_MISCCTL_RGBEN (1 << 7) +#define OSD_MISCCTL_RGBWIN (1 << 6) +#define OSD_MISCCTL_DMANG (1 << 6) +#define OSD_MISCCTL_TMON (1 << 5) +#define OSD_MISCCTL_RSEL (1 << 4) +#define OSD_MISCCTL_CPBSY (1 << 3) +#define OSD_MISCCTL_PPSW (1 << 2) +#define OSD_MISCCTL_PPRV (1 << 1) + +#define OSD_CLUTRAMYCB_Y_SHIFT 8 +#define OSD_CLUTRAMYCB_Y (0xff << 8) +#define OSD_CLUTRAMYCB_CB_SHIFT 0 +#define OSD_CLUTRAMYCB_CB (0xff << 0) + +#define OSD_CLUTRAMCR_CR_SHIFT 8 +#define OSD_CLUTRAMCR_CR (0xff << 8) +#define OSD_CLUTRAMCR_CADDR_SHIFT 0 +#define OSD_CLUTRAMCR_CADDR (0xff << 0) + +#define OSD_TRANSPVAL_RGBTRANS (0xffff << 0) + +#define OSD_TRANSPVALL_RGBL (0xffff << 0) + +#define OSD_TRANSPVALU_Y_SHIFT 8 +#define OSD_TRANSPVALU_Y (0xff << 8) +#define OSD_TRANSPVALU_RGBU_SHIFT 0 +#define OSD_TRANSPVALU_RGBU (0xff << 0) + +#define OSD_TRANSPBMPIDX_BMP1_SHIFT 8 +#define OSD_TRANSPBMPIDX_BMP1 (0xff << 8) +#define OSD_TRANSPBMPIDX_BMP0_SHIFT 0 +#define OSD_TRANSPBMPIDX_BMP0 0xff + +#endif /* _DAVINCI_VPBE_H_ */ diff --git a/drivers/media/video/davinci/vpbe_venc.c b/drivers/media/video/davinci/vpbe_venc.c new file mode 100644 index 0000000000000000000000000000000000000000..03a3e5c65ee78c53c017096ca55cf35d81ec0402 --- /dev/null +++ b/drivers/media/video/davinci/vpbe_venc.c @@ -0,0 +1,566 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 version 2. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "vpbe_venc_regs.h" + +#define MODULE_NAME VPBE_VENC_SUBDEV_NAME + +static int debug = 2; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level 0-2"); + +struct venc_state { + struct v4l2_subdev sd; + struct venc_callback *callback; + struct venc_platform_data *pdata; + struct device *pdev; + u32 output; + v4l2_std_id std; + spinlock_t lock; + void __iomem *venc_base; + void __iomem *vdaccfg_reg; +}; + +static inline struct venc_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct venc_state, sd); +} + +static inline u32 venc_read(struct v4l2_subdev *sd, u32 offset) +{ + struct venc_state *venc = to_state(sd); + + return readl(venc->venc_base + offset); +} + +static inline u32 venc_write(struct v4l2_subdev *sd, u32 offset, u32 val) +{ + struct venc_state *venc = to_state(sd); + + writel(val, (venc->venc_base + offset)); + + return val; +} + +static inline u32 venc_modify(struct v4l2_subdev *sd, u32 offset, + u32 val, u32 mask) +{ + u32 new_val = (venc_read(sd, offset) & ~mask) | (val & mask); + + venc_write(sd, offset, new_val); + + return new_val; +} + +static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val) +{ + struct venc_state *venc = to_state(sd); + + writel(val, venc->vdaccfg_reg); + + val = readl(venc->vdaccfg_reg); + + return val; +} + +/* This function sets the dac of the VPBE for various outputs + */ +static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index) +{ + switch (out_index) { + case 0: + v4l2_dbg(debug, 1, sd, "Setting output to Composite\n"); + venc_write(sd, VENC_DACSEL, 0); + break; + case 1: + v4l2_dbg(debug, 1, sd, "Setting output to S-Video\n"); + venc_write(sd, VENC_DACSEL, 0x210); + break; + case 2: + venc_write(sd, VENC_DACSEL, 0x543); + break; + default: + return -EINVAL; + } + + return 0; +} + +static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable) +{ + v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n"); + + if (benable) { + venc_write(sd, VENC_VMOD, 0); + venc_write(sd, VENC_CVBS, 0); + venc_write(sd, VENC_LCDOUT, 0); + venc_write(sd, VENC_HSPLS, 0); + venc_write(sd, VENC_HSTART, 0); + venc_write(sd, VENC_HVALID, 0); + venc_write(sd, VENC_HINT, 0); + venc_write(sd, VENC_VSPLS, 0); + venc_write(sd, VENC_VSTART, 0); + venc_write(sd, VENC_VVALID, 0); + venc_write(sd, VENC_VINT, 0); + venc_write(sd, VENC_YCCCTL, 0); + venc_write(sd, VENC_DACSEL, 0); + + } else { + venc_write(sd, VENC_VMOD, 0); + /* disable VCLK output pin enable */ + venc_write(sd, VENC_VIDCTL, 0x141); + + /* Disable output sync pins */ + venc_write(sd, VENC_SYNCCTL, 0); + + /* Disable DCLOCK */ + venc_write(sd, VENC_DCLKCTL, 0); + venc_write(sd, VENC_DRGBX1, 0x0000057C); + + /* Disable LCD output control (accepting default polarity) */ + venc_write(sd, VENC_LCDOUT, 0); + venc_write(sd, VENC_CMPNT, 0x100); + venc_write(sd, VENC_HSPLS, 0); + venc_write(sd, VENC_HINT, 0); + venc_write(sd, VENC_HSTART, 0); + venc_write(sd, VENC_HVALID, 0); + + venc_write(sd, VENC_VSPLS, 0); + venc_write(sd, VENC_VINT, 0); + venc_write(sd, VENC_VSTART, 0); + venc_write(sd, VENC_VVALID, 0); + + venc_write(sd, VENC_HSDLY, 0); + venc_write(sd, VENC_VSDLY, 0); + + venc_write(sd, VENC_YCCCTL, 0); + venc_write(sd, VENC_VSTARTA, 0); + + /* Set OSD clock and OSD Sync Adavance registers */ + venc_write(sd, VENC_OSDCLK0, 1); + venc_write(sd, VENC_OSDCLK1, 2); + } +} + +/* + * setting NTSC mode + */ +static int venc_set_ntsc(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; + + v4l2_dbg(debug, 2, sd, "venc_set_ntsc\n"); + + /* Setup clock at VPSS & VENC for SD */ + vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); + if (pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_525_60) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ + venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); + /* Set REC656 Mode */ + venc_write(sd, VENC_YCCCTL, 0x1); + venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS); + + venc_write(sd, VENC_VMOD, 0); + venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); + venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + venc_write(sd, VENC_DACTST, 0x0); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + + return 0; +} + +/* + * setting PAL mode + */ +static int venc_set_pal(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + + v4l2_dbg(debug, 2, sd, "venc_set_pal\n"); + + /* Setup clock at VPSS & VENC for SD */ + vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); + if (venc->pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_625_50) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ + venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); + /* Set REC656 Mode */ + venc_write(sd, VENC_YCCCTL, 0x1); + + venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT, + VENC_SYNCCTL_OVD); + venc_write(sd, VENC_VMOD, 0); + venc_modify(sd, VENC_VMOD, + (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, + (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); + venc_modify(sd, VENC_VMOD, + (1 << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + venc_write(sd, VENC_DACTST, 0x0); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + + return 0; +} + +/* + * venc_set_480p59_94 + * + * This function configures the video encoder to EDTV(525p) component setting. + */ +static int venc_set_480p59_94(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; + + v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n"); + + /* Setup clock at VPSS & VENC for SD */ + if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_480P59_94) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + venc_write(sd, VENC_OSDCLK0, 0); + venc_write(sd, VENC_OSDCLK1, 1); + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, + VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, + VENC_VDPRO_DAUPS); + venc_write(sd, VENC_VMOD, 0); + venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); + venc_modify(sd, VENC_VMOD, (HDTV_525P << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << + VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); + + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + + return 0; +} + +/* + * venc_set_625p + * + * This function configures the video encoder to HDTV(625p) component setting + */ +static int venc_set_576p50(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; + + v4l2_dbg(debug, 2, sd, "venc_set_576p50\n"); + + /* Setup clock at VPSS & VENC for SD */ + if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_576P50) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + venc_write(sd, VENC_OSDCLK0, 0); + venc_write(sd, VENC_OSDCLK1, 1); + + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, + VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, + VENC_VDPRO_DAUPS); + + venc_write(sd, VENC_VMOD, 0); + venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); + venc_modify(sd, VENC_VMOD, (HDTV_625P << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + + venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << + VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + + return 0; +} + +static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) +{ + v4l2_dbg(debug, 1, sd, "venc_s_std_output\n"); + + if (norm & V4L2_STD_525_60) + return venc_set_ntsc(sd); + else if (norm & V4L2_STD_625_50) + return venc_set_pal(sd); + + return -EINVAL; +} + +static int venc_s_dv_preset(struct v4l2_subdev *sd, + struct v4l2_dv_preset *dv_preset) +{ + v4l2_dbg(debug, 1, sd, "venc_s_dv_preset\n"); + + if (dv_preset->preset == V4L2_DV_576P50) + return venc_set_576p50(sd); + else if (dv_preset->preset == V4L2_DV_480P59_94) + return venc_set_480p59_94(sd); + + return -EINVAL; +} + +static int venc_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, + u32 config) +{ + struct venc_state *venc = to_state(sd); + int ret; + + v4l2_dbg(debug, 1, sd, "venc_s_routing\n"); + + ret = venc_set_dac(sd, output); + if (!ret) + venc->output = output; + + return ret; +} + +static long venc_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, + void *arg) +{ + u32 val; + + switch (cmd) { + case VENC_GET_FLD: + val = venc_read(sd, VENC_VSTAT); + *((int *)arg) = ((val & VENC_VSTAT_FIDST) == + VENC_VSTAT_FIDST); + break; + default: + v4l2_err(sd, "Wrong IOCTL cmd\n"); + break; + } + + return 0; +} + +static const struct v4l2_subdev_core_ops venc_core_ops = { + .ioctl = venc_ioctl, +}; + +static const struct v4l2_subdev_video_ops venc_video_ops = { + .s_routing = venc_s_routing, + .s_std_output = venc_s_std_output, + .s_dv_preset = venc_s_dv_preset, +}; + +static const struct v4l2_subdev_ops venc_ops = { + .core = &venc_core_ops, + .video = &venc_video_ops, +}; + +static int venc_initialize(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + int ret; + + /* Set default to output to composite and std to NTSC */ + venc->output = 0; + venc->std = V4L2_STD_525_60; + + ret = venc_s_routing(sd, 0, venc->output, 0); + if (ret < 0) { + v4l2_err(sd, "Error setting output during init\n"); + return -EINVAL; + } + + ret = venc_s_std_output(sd, venc->std); + if (ret < 0) { + v4l2_err(sd, "Error setting std during init\n"); + return -EINVAL; + } + + return ret; +} + +static int venc_device_get(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct venc_state **venc = data; + + if (strcmp(MODULE_NAME, pdev->name) == 0) + *venc = platform_get_drvdata(pdev); + + return 0; +} + +struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev, + const char *venc_name) +{ + struct venc_state *venc; + int err; + + err = bus_for_each_dev(&platform_bus_type, NULL, &venc, + venc_device_get); + if (venc == NULL) + return NULL; + + v4l2_subdev_init(&venc->sd, &venc_ops); + + strcpy(venc->sd.name, venc_name); + if (v4l2_device_register_subdev(v4l2_dev, &venc->sd) < 0) { + v4l2_err(v4l2_dev, + "vpbe unable to register venc sub device\n"); + return NULL; + } + if (venc_initialize(&venc->sd)) { + v4l2_err(v4l2_dev, + "vpbe venc initialization failed\n"); + return NULL; + } + + return &venc->sd; +} +EXPORT_SYMBOL(venc_sub_dev_init); + +static int venc_probe(struct platform_device *pdev) +{ + struct venc_state *venc; + struct resource *res; + int ret; + + venc = kzalloc(sizeof(struct venc_state), GFP_KERNEL); + if (venc == NULL) + return -ENOMEM; + + venc->pdev = &pdev->dev; + venc->pdata = pdev->dev.platform_data; + if (NULL == venc->pdata) { + dev_err(venc->pdev, "Unable to get platform data for" + " VENC sub device"); + ret = -ENOENT; + goto free_mem; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(venc->pdev, + "Unable to get VENC register address map\n"); + ret = -ENODEV; + goto free_mem; + } + + if (!request_mem_region(res->start, resource_size(res), "venc")) { + dev_err(venc->pdev, "Unable to reserve VENC MMIO region\n"); + ret = -ENODEV; + goto free_mem; + } + + venc->venc_base = ioremap_nocache(res->start, resource_size(res)); + if (!venc->venc_base) { + dev_err(venc->pdev, "Unable to map VENC IO space\n"); + ret = -ENODEV; + goto release_venc_mem_region; + } + + spin_lock_init(&venc->lock); + platform_set_drvdata(pdev, venc); + dev_notice(venc->pdev, "VENC sub device probe success\n"); + return 0; + +release_venc_mem_region: + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); +free_mem: + kfree(venc); + return ret; +} + +static int venc_remove(struct platform_device *pdev) +{ + struct venc_state *venc = platform_get_drvdata(pdev); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + iounmap((void *)venc->venc_base); + release_mem_region(res->start, resource_size(res)); + kfree(venc); + + return 0; +} + +static struct platform_driver venc_driver = { + .probe = venc_probe, + .remove = venc_remove, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + }, +}; + +static int venc_init(void) +{ + if (platform_driver_register(&venc_driver)) { + printk(KERN_ERR "Unable to register venc driver\n"); + return -ENODEV; + } + return 0; +} + +static void venc_exit(void) +{ + platform_driver_unregister(&venc_driver); + return; +} + +module_init(venc_init); +module_exit(venc_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("VPBE VENC Driver"); +MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/media/video/davinci/vpbe_venc_regs.h b/drivers/media/video/davinci/vpbe_venc_regs.h new file mode 100644 index 0000000000000000000000000000000000000000..947cb1510776a03de18c360735bd0cb68095101d --- /dev/null +++ b/drivers/media/video/davinci/vpbe_venc_regs.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2006-2010 Texas Instruments Inc + * + * 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 version 2.. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _VPBE_VENC_REGS_H +#define _VPBE_VENC_REGS_H + +/* VPBE Video Encoder / Digital LCD Subsystem Registers (VENC) */ +#define VENC_VMOD 0x00 +#define VENC_VIDCTL 0x04 +#define VENC_VDPRO 0x08 +#define VENC_SYNCCTL 0x0C +#define VENC_HSPLS 0x10 +#define VENC_VSPLS 0x14 +#define VENC_HINT 0x18 +#define VENC_HSTART 0x1C +#define VENC_HVALID 0x20 +#define VENC_VINT 0x24 +#define VENC_VSTART 0x28 +#define VENC_VVALID 0x2C +#define VENC_HSDLY 0x30 +#define VENC_VSDLY 0x34 +#define VENC_YCCCTL 0x38 +#define VENC_RGBCTL 0x3C +#define VENC_RGBCLP 0x40 +#define VENC_LINECTL 0x44 +#define VENC_CULLLINE 0x48 +#define VENC_LCDOUT 0x4C +#define VENC_BRTS 0x50 +#define VENC_BRTW 0x54 +#define VENC_ACCTL 0x58 +#define VENC_PWMP 0x5C +#define VENC_PWMW 0x60 +#define VENC_DCLKCTL 0x64 +#define VENC_DCLKPTN0 0x68 +#define VENC_DCLKPTN1 0x6C +#define VENC_DCLKPTN2 0x70 +#define VENC_DCLKPTN3 0x74 +#define VENC_DCLKPTN0A 0x78 +#define VENC_DCLKPTN1A 0x7C +#define VENC_DCLKPTN2A 0x80 +#define VENC_DCLKPTN3A 0x84 +#define VENC_DCLKHS 0x88 +#define VENC_DCLKHSA 0x8C +#define VENC_DCLKHR 0x90 +#define VENC_DCLKVS 0x94 +#define VENC_DCLKVR 0x98 +#define VENC_CAPCTL 0x9C +#define VENC_CAPDO 0xA0 +#define VENC_CAPDE 0xA4 +#define VENC_ATR0 0xA8 +#define VENC_ATR1 0xAC +#define VENC_ATR2 0xB0 +#define VENC_VSTAT 0xB8 +#define VENC_RAMADR 0xBC +#define VENC_RAMPORT 0xC0 +#define VENC_DACTST 0xC4 +#define VENC_YCOLVL 0xC8 +#define VENC_SCPROG 0xCC +#define VENC_CVBS 0xDC +#define VENC_CMPNT 0xE0 +#define VENC_ETMG0 0xE4 +#define VENC_ETMG1 0xE8 +#define VENC_ETMG2 0xEC +#define VENC_ETMG3 0xF0 +#define VENC_DACSEL 0xF4 +#define VENC_ARGBX0 0x100 +#define VENC_ARGBX1 0x104 +#define VENC_ARGBX2 0x108 +#define VENC_ARGBX3 0x10C +#define VENC_ARGBX4 0x110 +#define VENC_DRGBX0 0x114 +#define VENC_DRGBX1 0x118 +#define VENC_DRGBX2 0x11C +#define VENC_DRGBX3 0x120 +#define VENC_DRGBX4 0x124 +#define VENC_VSTARTA 0x128 +#define VENC_OSDCLK0 0x12C +#define VENC_OSDCLK1 0x130 +#define VENC_HVLDCL0 0x134 +#define VENC_HVLDCL1 0x138 +#define VENC_OSDHADV 0x13C +#define VENC_CLKCTL 0x140 +#define VENC_GAMCTL 0x144 +#define VENC_XHINTVL 0x174 + +/* bit definitions */ +#define VPBE_PCR_VENC_DIV (1 << 1) +#define VPBE_PCR_CLK_OFF (1 << 0) + +#define VENC_VMOD_VDMD_SHIFT 12 +#define VENC_VMOD_VDMD_YCBCR16 0 +#define VENC_VMOD_VDMD_YCBCR8 1 +#define VENC_VMOD_VDMD_RGB666 2 +#define VENC_VMOD_VDMD_RGB8 3 +#define VENC_VMOD_VDMD_EPSON 4 +#define VENC_VMOD_VDMD_CASIO 5 +#define VENC_VMOD_VDMD_UDISPQVGA 6 +#define VENC_VMOD_VDMD_STNLCD 7 +#define VENC_VMOD_VIE_SHIFT 1 +#define VENC_VMOD_VDMD (7 << 12) +#define VENC_VMOD_ITLCL (1 << 11) +#define VENC_VMOD_ITLC (1 << 10) +#define VENC_VMOD_NSIT (1 << 9) +#define VENC_VMOD_HDMD (1 << 8) +#define VENC_VMOD_TVTYP_SHIFT 6 +#define VENC_VMOD_TVTYP (3 << 6) +#define VENC_VMOD_SLAVE (1 << 5) +#define VENC_VMOD_VMD (1 << 4) +#define VENC_VMOD_BLNK (1 << 3) +#define VENC_VMOD_VIE (1 << 1) +#define VENC_VMOD_VENC (1 << 0) + +/* VMOD TVTYP options for HDMD=0 */ +#define SDTV_NTSC 0 +#define SDTV_PAL 1 +/* VMOD TVTYP options for HDMD=1 */ +#define HDTV_525P 0 +#define HDTV_625P 1 +#define HDTV_1080I 2 +#define HDTV_720P 3 + +#define VENC_VIDCTL_VCLKP (1 << 14) +#define VENC_VIDCTL_VCLKE_SHIFT 13 +#define VENC_VIDCTL_VCLKE (1 << 13) +#define VENC_VIDCTL_VCLKZ_SHIFT 12 +#define VENC_VIDCTL_VCLKZ (1 << 12) +#define VENC_VIDCTL_SYDIR_SHIFT 8 +#define VENC_VIDCTL_SYDIR (1 << 8) +#define VENC_VIDCTL_DOMD_SHIFT 4 +#define VENC_VIDCTL_DOMD (3 << 4) +#define VENC_VIDCTL_YCDIR_SHIFT 0 +#define VENC_VIDCTL_YCDIR (1 << 0) + +#define VENC_VDPRO_ATYCC_SHIFT 5 +#define VENC_VDPRO_ATYCC (1 << 5) +#define VENC_VDPRO_ATCOM_SHIFT 4 +#define VENC_VDPRO_ATCOM (1 << 4) +#define VENC_VDPRO_DAFRQ (1 << 3) +#define VENC_VDPRO_DAUPS (1 << 2) +#define VENC_VDPRO_CUPS (1 << 1) +#define VENC_VDPRO_YUPS (1 << 0) + +#define VENC_SYNCCTL_VPL_SHIFT 3 +#define VENC_SYNCCTL_VPL (1 << 3) +#define VENC_SYNCCTL_HPL_SHIFT 2 +#define VENC_SYNCCTL_HPL (1 << 2) +#define VENC_SYNCCTL_SYEV_SHIFT 1 +#define VENC_SYNCCTL_SYEV (1 << 1) +#define VENC_SYNCCTL_SYEH_SHIFT 0 +#define VENC_SYNCCTL_SYEH (1 << 0) +#define VENC_SYNCCTL_OVD_SHIFT 14 +#define VENC_SYNCCTL_OVD (1 << 14) + +#define VENC_DCLKCTL_DCKEC_SHIFT 11 +#define VENC_DCLKCTL_DCKEC (1 << 11) +#define VENC_DCLKCTL_DCKPW_SHIFT 0 +#define VENC_DCLKCTL_DCKPW (0x3f << 0) + +#define VENC_VSTAT_FIDST (1 << 4) + +#define VENC_CMPNT_MRGB_SHIFT 14 +#define VENC_CMPNT_MRGB (1 << 14) + +#endif /* _VPBE_VENC_REGS_H */ diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c index d93ad74a34c5fbe46631bb579836b03b6e4bb42a..49e4deb500430faf3be60475b5062cf7e5141921 100644 --- a/drivers/media/video/davinci/vpif_capture.c +++ b/drivers/media/video/davinci/vpif_capture.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -44,6 +43,7 @@ MODULE_DESCRIPTION("TI DaVinci VPIF Capture driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(VPIF_CAPTURE_VERSION); #define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg) #define vpif_dbg(level, debug, fmt, arg...) \ @@ -1677,7 +1677,6 @@ static int vpif_querycap(struct file *file, void *priv, { struct vpif_capture_config *config = vpif_dev->platform_data; - cap->version = VPIF_CAPTURE_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; strlcpy(cap->driver, "vpif capture", sizeof(cap->driver)); strlcpy(cap->bus_info, "DM646x Platform", sizeof(cap->bus_info)); @@ -2211,10 +2210,8 @@ static __init int vpif_probe(struct platform_device *pdev) vfd->v4l2_dev = &vpif_obj.v4l2_dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), - "DM646x_VPIFCapture_DRIVER_V%d.%d.%d", - (VPIF_CAPTURE_VERSION_CODE >> 16) & 0xff, - (VPIF_CAPTURE_VERSION_CODE >> 8) & 0xff, - (VPIF_CAPTURE_VERSION_CODE) & 0xff); + "DM646x_VPIFCapture_DRIVER_V%s", + VPIF_CAPTURE_VERSION); /* Set video_dev to the video device */ ch->video_dev = vfd; } diff --git a/drivers/media/video/davinci/vpif_capture.h b/drivers/media/video/davinci/vpif_capture.h index 7a4196dfdce19c649acb61b07e5f3600b719fc33..064550f5ce4adcdf638d943e6d2a7bdfbdf39451 100644 --- a/drivers/media/video/davinci/vpif_capture.h +++ b/drivers/media/video/davinci/vpif_capture.h @@ -23,7 +23,6 @@ /* Header files */ #include -#include #include #include #include @@ -33,11 +32,7 @@ #include "vpif.h" /* Macros */ -#define VPIF_MAJOR_RELEASE 0 -#define VPIF_MINOR_RELEASE 0 -#define VPIF_BUILD 1 -#define VPIF_CAPTURE_VERSION_CODE ((VPIF_MAJOR_RELEASE << 16) | \ - (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD) +#define VPIF_CAPTURE_VERSION "0.0.2" #define VPIF_VALID_FIELD(field) (((V4L2_FIELD_ANY == field) || \ (V4L2_FIELD_NONE == field)) || \ diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c index cdf659abdc2ab73ba172d85fc6a6aa75db4390c1..286f029100447552550d81c5b6c1d6b716fcf8e7 100644 --- a/drivers/media/video/davinci/vpif_display.c +++ b/drivers/media/video/davinci/vpif_display.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -47,6 +46,7 @@ MODULE_DESCRIPTION("TI DaVinci VPIF Display driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(VPIF_DISPLAY_VERSION); #define DM646X_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50) @@ -701,7 +701,6 @@ static int vpif_querycap(struct file *file, void *priv, { struct vpif_display_config *config = vpif_dev->platform_data; - cap->version = VPIF_DISPLAY_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; strlcpy(cap->driver, "vpif display", sizeof(cap->driver)); strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info)); @@ -1740,10 +1739,8 @@ static __init int vpif_probe(struct platform_device *pdev) vfd->v4l2_dev = &vpif_obj.v4l2_dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), - "DM646x_VPIFDisplay_DRIVER_V%d.%d.%d", - (VPIF_DISPLAY_VERSION_CODE >> 16) & 0xff, - (VPIF_DISPLAY_VERSION_CODE >> 8) & 0xff, - (VPIF_DISPLAY_VERSION_CODE) & 0xff); + "DM646x_VPIFDisplay_DRIVER_V%s", + VPIF_DISPLAY_VERSION); /* Set video_dev to the video device */ ch->video_dev = vfd; diff --git a/drivers/media/video/davinci/vpif_display.h b/drivers/media/video/davinci/vpif_display.h index b53aaa8830753bc18937d672d1fe2c5c046348a2..5d1936dafed25af340cb1ef91c261fd8fb76caa4 100644 --- a/drivers/media/video/davinci/vpif_display.h +++ b/drivers/media/video/davinci/vpif_display.h @@ -18,7 +18,6 @@ /* Header files */ #include -#include #include #include #include @@ -27,12 +26,7 @@ #include "vpif.h" /* Macros */ -#define VPIF_MAJOR_RELEASE (0) -#define VPIF_MINOR_RELEASE (0) -#define VPIF_BUILD (1) - -#define VPIF_DISPLAY_VERSION_CODE \ - ((VPIF_MAJOR_RELEASE << 16) | (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD) +#define VPIF_DISPLAY_VERSION "0.0.2" #define VPIF_VALID_FIELD(field) \ (((V4L2_FIELD_ANY == field) || (V4L2_FIELD_NONE == field)) || \ diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig index 3cb78f26df9033bb9068053f3ab80308d1a6ad04..281ee427c2ab6a20734b6af8082b3340cfbee144 100644 --- a/drivers/media/video/em28xx/Kconfig +++ b/drivers/media/video/em28xx/Kconfig @@ -3,7 +3,6 @@ config VIDEO_EM28XX depends on VIDEO_DEV && I2C select VIDEO_TUNER select VIDEO_TVEEPROM - depends on RC_CORE select VIDEOBUF_VMALLOC select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO @@ -40,7 +39,18 @@ config VIDEO_EM28XX_DVB select DVB_S921 if !DVB_FE_CUSTOMISE select DVB_DRXD if !DVB_FE_CUSTOMISE select DVB_CXD2820R if !DVB_FE_CUSTOMISE + select DVB_DRXK if !DVB_FE_CUSTOMISE + select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE select VIDEOBUF_DVB ---help--- This adds support for DVB cards based on the Empiatech em28xx chips. + +config VIDEO_EM28XX_RC + bool "EM28XX Remote Controller support" + depends on RC_CORE + depends on VIDEO_EM28XX + depends on !(RC_CORE=m && VIDEO_EM28XX=y) + default y + ---help--- + Enables Remote Controller support on em28xx driver. diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile index d0f093d1d0df23c887b7b5865d5fee5f4e74c794..38aaa004f57d6b64e6f6dd57ca3c85ddc2f31221 100644 --- a/drivers/media/video/em28xx/Makefile +++ b/drivers/media/video/em28xx/Makefile @@ -1,5 +1,7 @@ -em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \ - em28xx-input.o em28xx-vbi.o +em28xx-y := em28xx-video.o em28xx-i2c.o em28xx-cards.o +em28xx-y += em28xx-core.o em28xx-vbi.o + +em28xx-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-input.o em28xx-alsa-objs := em28xx-audio.o diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c index 3c48a72eb7de844138deff618c2d24ac062d5a42..cff0768afbf514183b50ba0e35e3bfdcbde43a6f 100644 --- a/drivers/media/video/em28xx/em28xx-audio.c +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -3,9 +3,9 @@ * * Copyright (C) 2006 Markus Rechberger * - * Copyright (C) 2007 Mauro Carvalho Chehab + * Copyright (C) 2007-2011 Mauro Carvalho Chehab * - Port to work with the in-kernel driver - * - Several cleanups + * - Cleanups, fixes, alsa-controls, etc. * * This driver is based on my previous au600 usb pstn audio driver * and inherits all the copyrights @@ -41,6 +41,7 @@ #include #include #include +#include #include #include "em28xx.h" @@ -212,9 +213,12 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); if (errCode) { + em28xx_errdev("submit of audio urb failed\n"); em28xx_deinit_isoc_audio(dev); + atomic_set(&dev->stream_started, 0); return errCode; } + } return 0; @@ -245,6 +249,7 @@ static struct snd_pcm_hardware snd_em28xx_hw_capture = { .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_MMAP_VALID, .formats = SNDRV_PCM_FMTBIT_S16_LE, @@ -276,24 +281,27 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) return -ENODEV; } - /* Sets volume, mute, etc */ + runtime->hw = snd_em28xx_hw_capture; + if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) { + if (dev->audio_ifnum) + dev->alt = 1; + else + dev->alt = 7; - dev->mute = 0; - mutex_lock(&dev->lock); - ret = em28xx_audio_analog_set(dev); - if (ret < 0) - goto err; + dprintk("changing alternate number on interface %d to %d\n", + dev->audio_ifnum, dev->alt); + usb_set_interface(dev->udev, dev->audio_ifnum, dev->alt); - runtime->hw = snd_em28xx_hw_capture; - if (dev->alt == 0 && dev->adev.users == 0) { - int errCode; - dev->alt = 7; - dprintk("changing alternate number to 7\n"); - errCode = usb_set_interface(dev->udev, 0, 7); - } + /* Sets volume, mute, etc */ + dev->mute = 0; + mutex_lock(&dev->lock); + ret = em28xx_audio_analog_set(dev); + if (ret < 0) + goto err; - dev->adev.users++; - mutex_unlock(&dev->lock); + dev->adev.users++; + mutex_unlock(&dev->lock); + } snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); dev->adev.capture_pcm_substream = substream; @@ -342,6 +350,8 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, ret = snd_pcm_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params)); + if (ret < 0) + return ret; format = params_format(hw_params); rate = params_rate(hw_params); channels = params_channels(hw_params); @@ -393,20 +403,24 @@ static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, int cmd) { struct em28xx *dev = snd_pcm_substream_chip(substream); - int retval; + int retval = 0; switch (cmd) { + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ + case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START: atomic_set(&dev->stream_started, 1); break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ + case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP: - atomic_set(&dev->stream_started, 1); + atomic_set(&dev->stream_started, 0); break; default: retval = -EINVAL; } schedule_work(&dev->wq_trigger); - return 0; + return retval; } static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream @@ -432,6 +446,179 @@ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, return vmalloc_to_page(pageptr); } +/* + * AC97 volume control support + */ +static int em28xx_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *info) +{ + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 2; + info->value.integer.min = 0; + info->value.integer.max = 0x1f; + + return 0; +} + +static int em28xx_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct em28xx *dev = snd_kcontrol_chip(kcontrol); + u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) | + (0x1f - (value->value.integer.value[1] & 0x1f)) << 8; + int rc; + + mutex_lock(&dev->lock); + rc = em28xx_read_ac97(dev, kcontrol->private_value); + if (rc < 0) + goto err; + + val |= rc & 0x8000; /* Preserve the mute flag */ + + rc = em28xx_write_ac97(dev, kcontrol->private_value, val); + if (rc < 0) + goto err; + + dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n", + (val & 0x8000) ? "muted " : "", + 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f), + val, (int)kcontrol->private_value); + +err: + mutex_unlock(&dev->lock); + return rc; +} + +static int em28xx_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct em28xx *dev = snd_kcontrol_chip(kcontrol); + int val; + + mutex_lock(&dev->lock); + val = em28xx_read_ac97(dev, kcontrol->private_value); + mutex_unlock(&dev->lock); + if (val < 0) + return val; + + dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n", + (val & 0x8000) ? "muted " : "", + 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f), + val, (int)kcontrol->private_value); + + value->value.integer.value[0] = 0x1f - (val & 0x1f); + value->value.integer.value[1] = 0x1f - ((val << 8) & 0x1f); + + return 0; +} + +static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct em28xx *dev = snd_kcontrol_chip(kcontrol); + u16 val = value->value.integer.value[0]; + int rc; + + mutex_lock(&dev->lock); + rc = em28xx_read_ac97(dev, kcontrol->private_value); + if (rc < 0) + goto err; + + if (val) + rc &= 0x1f1f; + else + rc |= 0x8000; + + rc = em28xx_write_ac97(dev, kcontrol->private_value, rc); + if (rc < 0) + goto err; + + dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n", + (val & 0x8000) ? "muted " : "", + 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f), + val, (int)kcontrol->private_value); + +err: + mutex_unlock(&dev->lock); + return rc; +} + +static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct em28xx *dev = snd_kcontrol_chip(kcontrol); + int val; + + mutex_lock(&dev->lock); + val = em28xx_read_ac97(dev, kcontrol->private_value); + mutex_unlock(&dev->lock); + if (val < 0) + return val; + + if (val & 0x8000) + value->value.integer.value[0] = 0; + else + value->value.integer.value[0] = 1; + + dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n", + (val & 0x8000) ? "muted " : "", + 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f), + val, (int)kcontrol->private_value); + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(em28xx_db_scale, -3450, 150, 0); + +static int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev, + char *name, int id) +{ + int err; + char ctl_name[44]; + struct snd_kcontrol *kctl; + struct snd_kcontrol_new tmp; + + memset (&tmp, 0, sizeof(tmp)); + tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER, + tmp.private_value = id, + tmp.name = ctl_name, + + /* Add Mute Control */ + sprintf(ctl_name, "%s Switch", name); + tmp.get = em28xx_vol_get_mute; + tmp.put = em28xx_vol_put_mute; + tmp.info = snd_ctl_boolean_mono_info; + kctl = snd_ctl_new1(&tmp, dev); + err = snd_ctl_add(card, kctl); + if (err < 0) + return err; + dprintk("Added control %s for ac97 volume control 0x%04x\n", + ctl_name, id); + + memset (&tmp, 0, sizeof(tmp)); + tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER, + tmp.private_value = id, + tmp.name = ctl_name, + + /* Add Volume Control */ + sprintf(ctl_name, "%s Volume", name); + tmp.get = em28xx_vol_get; + tmp.put = em28xx_vol_put; + tmp.info = em28xx_vol_info; + tmp.tlv.p = em28xx_db_scale, + kctl = snd_ctl_new1(&tmp, dev); + err = snd_ctl_add(card, kctl); + if (err < 0) + return err; + dprintk("Added control %s for ac97 volume control 0x%04x\n", + ctl_name, id); + + return 0; +} + +/* + * register/unregister code and data + */ static struct snd_pcm_ops snd_em28xx_pcm_capture = { .open = snd_em28xx_capture_open, .close = snd_em28xx_pcm_close, @@ -452,17 +639,17 @@ static int em28xx_audio_init(struct em28xx *dev) static int devnr; int err; - if (dev->has_alsa_audio != 1) { + if (!dev->has_alsa_audio || dev->audio_ifnum < 0) { /* This device does not support the extension (in this case the device is expecting the snd-usb-audio module or doesn't have analog audio support at all) */ return 0; } - printk(KERN_INFO "em28xx-audio.c: probing for em28x1 " - "non standard usbaudio\n"); + printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n"); printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus " "Rechberger\n"); + printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n"); err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0, &card); @@ -488,6 +675,22 @@ static int em28xx_audio_init(struct em28xx *dev) INIT_WORK(&dev->wq_trigger, audio_trigger); + if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { + em28xx_cvol_new(card, dev, "Video", AC97_VIDEO_VOL); + em28xx_cvol_new(card, dev, "Line In", AC97_LINEIN_VOL); + em28xx_cvol_new(card, dev, "Phone", AC97_PHONE_VOL); + em28xx_cvol_new(card, dev, "Microphone", AC97_PHONE_VOL); + em28xx_cvol_new(card, dev, "CD", AC97_CD_VOL); + em28xx_cvol_new(card, dev, "AUX", AC97_AUX_VOL); + em28xx_cvol_new(card, dev, "PCM", AC97_PCM_OUT_VOL); + + em28xx_cvol_new(card, dev, "Master", AC97_MASTER_VOL); + em28xx_cvol_new(card, dev, "Line", AC97_LINE_LEVEL_VOL); + em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO_VOL); + em28xx_cvol_new(card, dev, "LFE", AC97_LFE_MASTER_VOL); + em28xx_cvol_new(card, dev, "Surround", AC97_SURR_MASTER_VOL); + } + err = snd_card_register(card); if (err < 0) { snd_card_free(card); @@ -538,7 +741,7 @@ static void __exit em28xx_alsa_unregister(void) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Markus Rechberger "); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab "); MODULE_DESCRIPTION("Em28xx Audio driver"); module_init(em28xx_alsa_register); diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 4e37375decf54dbdea4e3c9617fcf52b9201912f..3e3959fee4195cad5bfc6070d42250f57e2c96a2 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -289,7 +289,7 @@ static struct em28xx_reg_seq leadership_reset[] = { { -1, -1, -1, -1}, }; -/* 2013:024f PCTV Systems nanoStick T2 290e +/* 2013:024f PCTV nanoStick T2 290e * GPIO_6 - demod reset * GPIO_7 - LED */ @@ -300,6 +300,23 @@ static struct em28xx_reg_seq pctv_290e[] = { {-1, -1, -1, -1}, }; +#if 0 +static struct em28xx_reg_seq terratec_h5_gpio[] = { + {EM28XX_R08_GPIO, 0xff, 0xff, 10}, + {EM2874_R80_GPIO, 0xf6, 0xff, 100}, + {EM2874_R80_GPIO, 0xf2, 0xff, 50}, + {EM2874_R80_GPIO, 0xf6, 0xff, 50}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq terratec_h5_digital[] = { + {EM2874_R80_GPIO, 0xf6, 0xff, 10}, + {EM2874_R80_GPIO, 0xe6, 0xff, 100}, + {EM2874_R80_GPIO, 0xa6, 0xff, 10}, + { -1, -1, -1, -1}, +}; +#endif + /* * Board definitions */ @@ -843,6 +860,19 @@ struct em28xx_board em28xx_boards[] = { .gpio = terratec_cinergy_USB_XS_FR_analog, } }, }, + [EM2884_BOARD_TERRATEC_H5] = { + .name = "Terratec Cinergy H5", + .has_dvb = 1, +#if 0 + .tuner_type = TUNER_PHILIPS_TDA8290, + .tuner_addr = 0x41, + .dvb_gpio = terratec_h5_digital, /* FIXME: probably wrong */ + .tuner_gpio = terratec_h5_gpio, +#endif + .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, + }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { .name = "Hauppauge WinTV HVR 900", .tda9887_conf = TDA9887_PRESENT, @@ -1259,7 +1289,7 @@ struct em28xx_board em28xx_boards[] = { } }, }, - [EM2874_LEADERSHIP_ISDBT] = { + [EM2874_BOARD_LEADERSHIP_ISDBT] = { .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ, @@ -1319,7 +1349,6 @@ struct em28xx_board em28xx_boards[] = { }, [EM2880_BOARD_KWORLD_DVB_305U] = { .name = "KWorld DVB-T 305U", - .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, @@ -1770,16 +1799,16 @@ struct em28xx_board em28xx_boards[] = { .dvb_gpio = kworld_a340_digital, .tuner_gpio = default_tuner_gpio, }, - /* 2013:024f PCTV Systems nanoStick T2 290e. + /* 2013:024f PCTV nanoStick T2 290e. * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 */ [EM28174_BOARD_PCTV_290E] = { + .name = "PCTV nanoStick T2 290e", .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ, - .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, - .name = "PCTV Systems nanoStick T2 290e", .tuner_type = TUNER_ABSENT, .tuner_gpio = pctv_290e, .has_dvb = 1, + .ir_codes = RC_MAP_PINNACLE_PCTV_HD, }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); @@ -1855,8 +1884,10 @@ struct usb_device_id em28xx_id_table[] = { { USB_DEVICE(0x0ccd, 0x0042), .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS }, { USB_DEVICE(0x0ccd, 0x0043), - .driver_info = EM2870_BOARD_TERRATEC_XS }, - { USB_DEVICE(0x0ccd, 0x0047), + .driver_info = EM2884_BOARD_TERRATEC_H5 }, + { USB_DEVICE(0x0ccd, 0x10a2), /* Rev. 1 */ + .driver_info = EM2884_BOARD_TERRATEC_H5 }, + { USB_DEVICE(0x0ccd, 0x10ad), /* Rev. 2 */ .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, { USB_DEVICE(0x0ccd, 0x0084), .driver_info = EM2860_BOARD_TERRATEC_AV350 }, @@ -1937,7 +1968,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = { {0x77800080, EM2860_BOARD_TVP5150_REFERENCE_DESIGN, TUNER_ABSENT}, {0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC}, {0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF}, - {0x6b800080, EM2874_LEADERSHIP_ISDBT, TUNER_ABSENT}, + {0x6b800080, EM2874_BOARD_LEADERSHIP_ISDBT, TUNER_ABSENT}, }; /* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */ @@ -2660,10 +2691,9 @@ void em28xx_card_setup(struct em28xx *dev) .addr = 0xba >> 1, .platform_data = &pdata, }; - struct v4l2_subdev *sd; pdata.xtal = dev->sensor_xtal; - sd = v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap, + v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap, &mt9v011_info, NULL); } @@ -2842,11 +2872,26 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, em28xx_info("chip ID is em2882/em2883\n"); dev->wait_after_write = 0; break; + case CHIP_ID_EM2884: + em28xx_info("chip ID is em2884\n"); + dev->reg_gpio_num = EM2874_R80_GPIO; + dev->wait_after_write = 0; + break; default: em28xx_info("em28xx chip ID = %d\n", dev->chip_id); } } + if (dev->is_audio_only) { + errCode = em28xx_audio_setup(dev); + if (errCode) + return -ENODEV; + em28xx_add_into_devlist(dev); + em28xx_init_extension(dev); + + return 0; + } + /* Prepopulate cached GPO register content */ retval = em28xx_read_reg(dev, dev->reg_gpo_num); if (retval >= 0) @@ -2947,6 +2992,9 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, return retval; } +/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ +#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) + /* * em28xx_usb_probe() * checks for supported devices @@ -2956,15 +3004,15 @@ static int em28xx_usb_probe(struct usb_interface *interface, { const struct usb_endpoint_descriptor *endpoint; struct usb_device *udev; - struct usb_interface *uif; struct em28xx *dev = NULL; int retval; - int i, nr, ifnum, isoc_pipe; + bool is_audio_only = false, has_audio = false; + int i, nr, isoc_pipe; + const int ifnum = interface->altsetting[0].desc.bInterfaceNumber; char *speed; char descr[255] = ""; udev = usb_get_dev(interface_to_usbdev(interface)); - ifnum = interface->altsetting[0].desc.bInterfaceNumber; /* Check to see next free device and mark as used */ nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS); @@ -2984,6 +3032,19 @@ static int em28xx_usb_probe(struct usb_interface *interface, goto err; } + /* Get endpoints */ + for (i = 0; i < interface->num_altsetting; i++) { + int ep; + + for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) { + struct usb_host_endpoint *e; + e = &interface->altsetting[i].endpoint[ep]; + + if (e->desc.bEndpointAddress == 0x83) + has_audio = true; + } + } + endpoint = &interface->cur_altsetting->endpoint[0].desc; /* check if the device has the iso in endpoint at the correct place */ @@ -3003,19 +3064,22 @@ static int em28xx_usb_probe(struct usb_interface *interface, check_interface = 0; if (!check_interface) { - em28xx_err(DRIVER_NAME " video device (%04x:%04x): " - "interface %i, class %i found.\n", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), - ifnum, - interface->altsetting[0].desc.bInterfaceClass); - - em28xx_err(DRIVER_NAME " This is an anciliary " - "interface not used by the driver\n"); - - em28xx_devused &= ~(1<descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + ifnum, + interface->altsetting[0].desc.bInterfaceClass); + em28xx_err(DRIVER_NAME " This is an anciliary " + "interface not used by the driver\n"); + + em28xx_devused &= ~(1<descriptor.idVendor), @@ -3054,6 +3118,11 @@ static int em28xx_usb_probe(struct usb_interface *interface, ifnum, interface->altsetting->desc.bInterfaceNumber); + if (has_audio) + printk(KERN_INFO DRIVER_NAME + ": Audio Vendor Class interface %i found\n", + ifnum); + /* * Make sure we have 480 Mbps of bandwidth, otherwise things like * video stream wouldn't likely work, since 12 Mbps is generally @@ -3089,10 +3158,13 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->devno = nr; dev->model = id->driver_info; dev->alt = -1; + dev->is_audio_only = is_audio_only; + dev->has_alsa_audio = has_audio; + dev->audio_ifnum = ifnum; /* Checks if audio is provided by some interface */ for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { - uif = udev->config->interface[i]; + struct usb_interface *uif = udev->config->interface[i]; if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { dev->has_audio_class = 1; break; @@ -3100,9 +3172,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, } /* compute alternate max packet sizes */ - uif = udev->actconfig->interface[0]; - - dev->num_alt = uif->num_altsetting; + dev->num_alt = interface->num_altsetting; dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL); if (dev->alt_max_pkt_size == NULL) { @@ -3114,14 +3184,21 @@ static int em28xx_usb_probe(struct usb_interface *interface, } for (i = 0; i < dev->num_alt ; i++) { - u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize); - dev->alt_max_pkt_size[i] = - (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); + u16 tmp = le16_to_cpu(interface->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize); + unsigned int size = tmp & 0x7ff; + + if (udev->speed == USB_SPEED_HIGH) + size = size * hb_mult(tmp); + + dev->alt_max_pkt_size[i] = size; } if ((card[nr] >= 0) && (card[nr] < em28xx_bcount)) dev->model = card[nr]; + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, dev); + /* allocate device struct */ mutex_init(&dev->lock); mutex_lock(&dev->lock); @@ -3133,9 +3210,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, goto err; } - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); - request_modules(dev); /* Should be the last thing to do, to avoid newer udev's to @@ -3164,6 +3238,13 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) if (!dev) return; + if (dev->is_audio_only) { + mutex_lock(&dev->lock); + em28xx_close_extension(dev); + mutex_unlock(&dev->lock); + return; + } + em28xx_info("disconnecting %s\n", dev->vdev->name); flush_request_modules(dev); diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index e33f145d867ae923772768dcc02cb08a5de54eec..57b1b5c6d88585521b06dcf647424669e7a2de60 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -211,6 +211,7 @@ int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val) { return em28xx_write_regs(dev, reg, &val, 1); } +EXPORT_SYMBOL_GPL(em28xx_write_reg); /* * em28xx_write_reg_bits() @@ -286,6 +287,7 @@ int em28xx_read_ac97(struct em28xx *dev, u8 reg) return ret; return le16_to_cpu(val); } +EXPORT_SYMBOL_GPL(em28xx_read_ac97); /* * em28xx_write_ac97() @@ -313,13 +315,14 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val) return 0; } +EXPORT_SYMBOL_GPL(em28xx_write_ac97); -struct em28xx_vol_table { +struct em28xx_vol_itable { enum em28xx_amux mux; u8 reg; }; -static struct em28xx_vol_table inputs[] = { +static struct em28xx_vol_itable inputs[] = { { EM28XX_AMUX_VIDEO, AC97_VIDEO_VOL }, { EM28XX_AMUX_LINE_IN, AC97_LINEIN_VOL }, { EM28XX_AMUX_PHONE, AC97_PHONE_VOL }, @@ -403,7 +406,12 @@ static int em28xx_set_audio_source(struct em28xx *dev) return ret; } -static const struct em28xx_vol_table outputs[] = { +struct em28xx_vol_otable { + enum em28xx_aout mux; + u8 reg; +}; + +static const struct em28xx_vol_otable outputs[] = { { EM28XX_AOUT_MASTER, AC97_MASTER_VOL }, { EM28XX_AOUT_LINE, AC97_LINE_LEVEL_VOL }, { EM28XX_AOUT_MONO, AC97_MASTER_MONO_VOL }, @@ -492,17 +500,13 @@ int em28xx_audio_setup(struct em28xx *dev) if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) { /* Digital only device - don't load any alsa module */ - dev->audio_mode.has_audio = 0; - dev->has_audio_class = 0; - dev->has_alsa_audio = 0; + dev->audio_mode.has_audio = false; + dev->has_audio_class = false; + dev->has_alsa_audio = false; return 0; } - /* If device doesn't support Usb Audio Class, use vendor class */ - if (!dev->has_audio_class) - dev->has_alsa_audio = 1; - - dev->audio_mode.has_audio = 1; + dev->audio_mode.has_audio = true; /* See how this device is configured */ cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); @@ -512,8 +516,8 @@ int em28xx_audio_setup(struct em28xx *dev) cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */ } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) { /* The device doesn't have vendor audio at all */ - dev->has_alsa_audio = 0; - dev->audio_mode.has_audio = 0; + dev->has_alsa_audio = false; + dev->audio_mode.has_audio = false; return 0; } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == EM28XX_CHIPCFG_I2S_3_SAMPRATES) { @@ -542,8 +546,8 @@ int em28xx_audio_setup(struct em28xx *dev) */ em28xx_warn("AC97 chip type couldn't be determined\n"); dev->audio_mode.ac97 = EM28XX_NO_AC97; - dev->has_alsa_audio = 0; - dev->audio_mode.has_audio = 0; + dev->has_alsa_audio = false; + dev->audio_mode.has_audio = false; goto init_audio; } @@ -615,7 +619,9 @@ int em28xx_capture_start(struct em28xx *dev, int start) { int rc; - if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) { + if (dev->chip_id == CHIP_ID_EM2874 || + dev->chip_id == CHIP_ID_EM2884 || + dev->chip_id == CHIP_ID_EM28174) { /* The Transport Stream Enable Register moved in em2874 */ if (!start) { rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, @@ -884,6 +890,7 @@ int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio) } return rc; } +EXPORT_SYMBOL_GPL(em28xx_gpio_set); int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode) { @@ -917,7 +924,7 @@ EXPORT_SYMBOL_GPL(em28xx_set_mode); static void em28xx_irq_callback(struct urb *urb) { struct em28xx *dev = urb->context; - int rc, i; + int i; switch (urb->status) { case 0: /* success */ @@ -934,7 +941,7 @@ static void em28xx_irq_callback(struct urb *urb) /* Copy data from URB */ spin_lock(&dev->slock); - rc = dev->isoc_ctl.isoc_copy(dev, urb); + dev->isoc_ctl.isoc_copy(dev, urb); spin_unlock(&dev->slock); /* Reset urb buffers */ @@ -1106,17 +1113,19 @@ EXPORT_SYMBOL_GPL(em28xx_init_isoc); int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev) { unsigned int chip_cfg2; - unsigned int packet_size = 564; - - if (dev->chip_id == CHIP_ID_EM2874) { - /* FIXME - for now assume 564 like it was before, but the - em2874 code should be added to return the proper value... */ - packet_size = 564; - } else if (dev->chip_id == CHIP_ID_EM28174) { - /* FIXME same as em2874. 564 was enough for 22 Mbit DVB-T - but too much for 44 Mbit DVB-C. */ - packet_size = 752; - } else { + unsigned int packet_size; + + switch (dev->chip_id) { + case CHIP_ID_EM2710: + case CHIP_ID_EM2750: + case CHIP_ID_EM2800: + case CHIP_ID_EM2820: + case CHIP_ID_EM2840: + case CHIP_ID_EM2860: + /* No DVB support */ + return -EINVAL; + case CHIP_ID_EM2870: + case CHIP_ID_EM2883: /* TS max packet size stored in bits 1-0 of R01 */ chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2); switch (chip_cfg2 & EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK) { @@ -1133,9 +1142,24 @@ int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev) packet_size = 752; break; } + break; + case CHIP_ID_EM2874: + /* + * FIXME: for now assumes 564 like it was before, but the + * em2874 code should be added to return the proper value + */ + packet_size = 564; + break; + case CHIP_ID_EM2884: + case CHIP_ID_EM28174: + default: + /* + * FIXME: same as em2874. 564 was enough for 22 Mbit DVB-T + * but not enough for 44 Mbit DVB-C. + */ + packet_size = 752; } - em28xx_coredbg("dvb max packet size=%d\n", packet_size); return packet_size; } EXPORT_SYMBOL_GPL(em28xx_isoc_dvb_max_packetsize); diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index 7904ca4b69134d1fdb4af0d3d0a89b0acbeffdee..e5916dee40945b8fd250582615904f5c8b381e98 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -1,7 +1,7 @@ /* DVB device driver for em28xx - (c) 2008 Mauro Carvalho Chehab + (c) 2008-2011 Mauro Carvalho Chehab (c) 2008 Devin Heitmueller - Fixes for the driver to properly work with HVR-950 @@ -40,6 +40,8 @@ #include "s921.h" #include "drxd.h" #include "cxd2820r.h" +#include "tda18271c2dd.h" +#include "drxk.h" MODULE_DESCRIPTION("driver for em28xx based DVB cards"); MODULE_AUTHOR("Mauro Carvalho Chehab "); @@ -73,6 +75,11 @@ struct em28xx_dvb { struct dmx_frontend fe_hw; struct dmx_frontend fe_mem; struct dvb_net net; + + /* Due to DRX-K - probably need changes */ + int (*gate_ctrl)(struct dvb_frontend *, int); + struct semaphore pll_mutex; + bool dont_attach_fe1; }; @@ -160,6 +167,11 @@ static int start_streaming(struct em28xx_dvb *dvb) return rc; max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev); + if (max_dvb_packet_size < 0) + return max_dvb_packet_size; + dprintk(1, "Using %d buffers each with %d bytes\n", + EM28XX_DVB_NUM_BUFS, + max_dvb_packet_size); return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS, EM28XX_DVB_NUM_BUFS, max_dvb_packet_size, @@ -295,6 +307,79 @@ static struct drxd_config em28xx_drxd = { .disable_i2c_gate_ctrl = 1, }; +struct drxk_config terratec_h5_drxk = { + .adr = 0x29, + .single_master = 1, + .no_i2c_bridge = 1, + .microcode_name = "dvb-usb-terratec-h5-drxk.fw", +}; + +static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct em28xx_dvb *dvb = fe->sec_priv; + int status; + + if (!dvb) + return -EINVAL; + + if (enable) { + down(&dvb->pll_mutex); + status = dvb->gate_ctrl(fe, 1); + } else { + status = dvb->gate_ctrl(fe, 0); + up(&dvb->pll_mutex); + } + return status; +} + +static void terratec_h5_init(struct em28xx *dev) +{ + int i; + struct em28xx_reg_seq terratec_h5_init[] = { + {EM28XX_R08_GPIO, 0xff, 0xff, 10}, + {EM2874_R80_GPIO, 0xf6, 0xff, 100}, + {EM2874_R80_GPIO, 0xf2, 0xff, 50}, + {EM2874_R80_GPIO, 0xf6, 0xff, 100}, + { -1, -1, -1, -1}, + }; + struct em28xx_reg_seq terratec_h5_end[] = { + {EM2874_R80_GPIO, 0xe6, 0xff, 100}, + {EM2874_R80_GPIO, 0xa6, 0xff, 50}, + {EM2874_R80_GPIO, 0xe6, 0xff, 100}, + { -1, -1, -1, -1}, + }; + struct { + unsigned char r[4]; + int len; + } regs[] = { + {{ 0x06, 0x02, 0x00, 0x31 }, 4}, + {{ 0x01, 0x02 }, 2}, + {{ 0x01, 0x02, 0x00, 0xc6 }, 4}, + {{ 0x01, 0x00 }, 2}, + {{ 0x01, 0x00, 0xff, 0xaf }, 4}, + {{ 0x01, 0x00, 0x03, 0xa0 }, 4}, + {{ 0x01, 0x00 }, 2}, + {{ 0x01, 0x00, 0x73, 0xaf }, 4}, + {{ 0x04, 0x00 }, 2}, + {{ 0x00, 0x04 }, 2}, + {{ 0x00, 0x04, 0x00, 0x0a }, 4}, + {{ 0x04, 0x14 }, 2}, + {{ 0x04, 0x14, 0x00, 0x00 }, 4}, + }; + + em28xx_gpio_set(dev, terratec_h5_init); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); + msleep(10); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45); + msleep(10); + + dev->i2c_client.addr = 0x82 >> 1; + + for (i = 0; i < ARRAY_SIZE(regs); i++) + i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); + em28xx_gpio_set(dev, terratec_h5_end); +}; + static int mt352_terratec_xs_init(struct dvb_frontend *fe) { /* Values extracted from a USB trace of the Terratec Windows driver */ @@ -516,7 +601,7 @@ static void unregister_dvb(struct em28xx_dvb *dvb) if (dvb->fe[1]) dvb_unregister_frontend(dvb->fe[1]); dvb_unregister_frontend(dvb->fe[0]); - if (dvb->fe[1]) + if (dvb->fe[1] && !dvb->dont_attach_fe1) dvb_frontend_detach(dvb->fe[1]); dvb_frontend_detach(dvb->fe[0]); dvb_unregister_adapter(&dvb->adapter); @@ -546,7 +631,7 @@ static int dvb_init(struct em28xx *dev) em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); /* init frontend */ switch (dev->model) { - case EM2874_LEADERSHIP_ISDBT: + case EM2874_BOARD_LEADERSHIP_ISDBT: dvb->fe[0] = dvb_attach(s921_attach, &sharp_isdbt, &dev->i2c_adap); @@ -688,6 +773,41 @@ static int dvb_init(struct em28xx *dev) /* leave FE 0 still active */ } } + break; + case EM2884_BOARD_TERRATEC_H5: + terratec_h5_init(dev); + + dvb->dont_attach_fe1 = 1; + + dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap, &dvb->fe[1]); + if (!dvb->fe[0]) { + result = -EINVAL; + goto out_free; + } + + /* FIXME: do we need a pll semaphore? */ + dvb->fe[0]->sec_priv = dvb; + sema_init(&dvb->pll_mutex, 1); + dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl; + dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl; + dvb->fe[1]->id = 1; + + /* Attach tda18271 to DVB-C frontend */ + if (dvb->fe[0]->ops.i2c_gate_ctrl) + dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1); + if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap, 0x60)) { + result = -EINVAL; + goto out_free; + } + if (dvb->fe[0]->ops.i2c_gate_ctrl) + dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0); + + /* Hack - needed by drxk/tda18271c2dd */ + dvb->fe[1]->tuner_priv = dvb->fe[0]->tuner_priv; + memcpy(&dvb->fe[1]->ops.tuner_ops, + &dvb->fe[0]->ops.tuner_ops, + sizeof(dvb->fe[0]->ops.tuner_ops)); + break; default: em28xx_errdev("/2: The frontend of your DVB/ATSC card" diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index 4739fc7e6eb360397f6e21c426b805206ef20d4a..36f5a9bc8b765b56129dd6368d88146d938edb72 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c @@ -181,16 +181,25 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr, /* * em28xx_i2c_send_bytes() - * untested for more than 4 bytes */ static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf, short len, int stop) { int wrcount = 0; struct em28xx *dev = (struct em28xx *)data; + int write_timeout, ret; wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); + /* Seems to be required after a write */ + for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0; + write_timeout -= 5) { + ret = dev->em28xx_read_reg(dev, 0x05); + if (!ret) + break; + msleep(5); + } + return wrcount; } @@ -218,9 +227,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr, */ static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr) { - char msg; int ret; - msg = addr; ret = dev->em28xx_read_reg_req(dev, 2, addr); if (ret < 0) { @@ -332,7 +339,9 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) struct em28xx_eeprom *em_eeprom = (void *)eedata; int i, err, size = len, block; - if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) { + if (dev->chip_id == CHIP_ID_EM2874 || + dev->chip_id == CHIP_ID_EM28174 || + dev->chip_id == CHIP_ID_EM2884) { /* Empia switched to a 16-bit addressable eeprom in newer devices. While we could certainly write a routine to read the eeprom, there is nothing of use in there that cannot be diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index ba1ba8648c8169c074fdcb497643d6ad05a5197b..5d12b14282e3dc19353f62831b3d5df1d7757f6f 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -372,6 +372,7 @@ int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type) ir->get_key = default_polling_getkey; break; case CHIP_ID_EM2874: + case CHIP_ID_EM28174: ir->get_key = em2874_polling_getkey; em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1); break; diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h index e92a28ede434d803cc56e2ad7aaa91fcc454a512..66f792361b97dee12d7b91c9839c12f71600f8a2 100644 --- a/drivers/media/video/em28xx/em28xx-reg.h +++ b/drivers/media/video/em28xx/em28xx-reg.h @@ -201,6 +201,7 @@ enum em28xx_chip_id { CHIP_ID_EM2870 = 35, CHIP_ID_EM2883 = 36, CHIP_ID_EM2874 = 65, + CHIP_ID_EM2884 = 68, CHIP_ID_EM28174 = 113, }; diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 7b6461d2d1ff3f1a2ef9b25560772d7a34909b08..d176dc0394e2f9c276c4e333f695c7c91f39a563 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -50,7 +49,8 @@ "Sascha Sommer " #define DRIVER_DESC "Empia em28xx based USB video device driver" -#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 1, 2) + +#define EM28XX_VERSION "0.1.3" #define em28xx_videodbg(fmt, arg...) do {\ if (video_debug) \ @@ -72,6 +72,7 @@ do {\ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); +MODULE_VERSION(EM28XX_VERSION); static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; @@ -1757,8 +1758,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->version = EM28XX_VERSION_CODE; - cap->capabilities = V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE | @@ -1976,7 +1975,6 @@ static int radio_querycap(struct file *file, void *priv, strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->version = EM28XX_VERSION_CODE; cap->capabilities = V4L2_CAP_TUNER; return 0; } @@ -2450,10 +2448,8 @@ int em28xx_register_analog_devices(struct em28xx *dev) u8 val; int ret; - printk(KERN_INFO "%s: v4l2 driver version %d.%d.%d\n", - dev->name, - (EM28XX_VERSION_CODE >> 16) & 0xff, - (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff); + printk(KERN_INFO "%s: v4l2 driver version %s\n", + dev->name, EM28XX_VERSION); /* set default norm */ dev->norm = em28xx_video_template.current_norm; diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 3cca3312245086aed60a7ab0a2e65a525b8a2e56..d80658bf3da9f70df94b60c4cdd2ed042b470f7b 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -117,9 +117,9 @@ #define EM2800_BOARD_VC211A 74 #define EM2882_BOARD_DIKOM_DK300 75 #define EM2870_BOARD_KWORLD_A340 76 -#define EM2874_LEADERSHIP_ISDBT 77 +#define EM2874_BOARD_LEADERSHIP_ISDBT 77 #define EM28174_BOARD_PCTV_290E 78 - +#define EM2884_BOARD_TERRATEC_H5 79 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 @@ -487,6 +487,8 @@ struct em28xx { int devno; /* marks the number of this device */ enum em28xx_chip_id chip_id; + int audio_ifnum; + struct v4l2_device v4l2_dev; struct em28xx_board board; @@ -503,6 +505,7 @@ struct em28xx { unsigned int has_audio_class:1; unsigned int has_alsa_audio:1; + unsigned int is_audio_only:1; /* Controls audio streaming */ struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ @@ -697,6 +700,9 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg); void em28xx_release_resources(struct em28xx *dev); /* Provided by em28xx-input.c */ + +#ifdef CONFIG_VIDEO_EM28XX_RC + int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, @@ -709,6 +715,20 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev); int em28xx_ir_init(struct em28xx *dev); int em28xx_ir_fini(struct em28xx *dev); +#else + +#define em28xx_get_key_terratec NULL +#define em28xx_get_key_em_haup NULL +#define em28xx_get_key_pinnacle_usb_grey NULL +#define em28xx_get_key_winfast_usbii_deluxe NULL + +static inline void em28xx_register_snapshot_button(struct em28xx *dev) {} +static inline void em28xx_deregister_snapshot_button(struct em28xx *dev) {} +static inline int em28xx_ir_init(struct em28xx *dev) { return 0; } +static inline int em28xx_ir_fini(struct em28xx *dev) { return 0; } + +#endif + /* Provided by em28xx-vbi.c */ extern struct videobuf_queue_ops em28xx_vbi_qops; diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h index bf66189cb26de1fba4f58884e458b89adb08d2b7..14bb907d650e123b4fe2be6a2366c5618f596f82 100644 --- a/drivers/media/video/et61x251/et61x251.h +++ b/drivers/media/video/et61x251/et61x251.h @@ -21,7 +21,6 @@ #ifndef _ET61X251_H_ #define _ET61X251_H_ -#include #include #include #include diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index a982750dcef10ad0d73f36be93246c4e1051a80b..9a1e80a1e1459824b95da0abe23dc00f8e8393e7 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -18,6 +18,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * ***************************************************************************/ +#include #include #include #include @@ -48,8 +49,7 @@ #define ET61X251_MODULE_AUTHOR "(C) 2006-2007 Luca Risolia" #define ET61X251_AUTHOR_EMAIL "" #define ET61X251_MODULE_LICENSE "GPL" -#define ET61X251_MODULE_VERSION "1:1.09" -#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 9) +#define ET61X251_MODULE_VERSION "1.1.10" /*****************************************************************************/ @@ -1579,7 +1579,7 @@ et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg) { struct v4l2_capability cap = { .driver = "et61x251", - .version = ET61X251_MODULE_VERSION_CODE, + .version = LINUX_VERSION_CODE, .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING, }; @@ -2480,16 +2480,8 @@ static long et61x251_ioctl_v4l2(struct file *filp, case VIDIOC_S_PARM: return et61x251_vidioc_s_parm(cam, arg); - case VIDIOC_G_STD: - case VIDIOC_S_STD: - case VIDIOC_QUERYSTD: - case VIDIOC_ENUMSTD: - case VIDIOC_QUERYMENU: - case VIDIOC_ENUM_FRAMEINTERVALS: - return -EINVAL; - default: - return -EINVAL; + return -ENOTTY; } } diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c index 908d7012c3f23652507adbc77cf8f2a5729428f8..27cb197d0bd6e911696750e988a85e5af0a5994f 100644 --- a/drivers/media/video/fsl-viu.c +++ b/drivers/media/video/fsl-viu.c @@ -23,19 +23,13 @@ #include #include #include -#include #include #include #include #include #define DRV_NAME "fsl_viu" -#define VIU_MAJOR_VERSION 0 -#define VIU_MINOR_VERSION 5 -#define VIU_RELEASE 0 -#define VIU_VERSION KERNEL_VERSION(VIU_MAJOR_VERSION, \ - VIU_MINOR_VERSION, \ - VIU_RELEASE) +#define VIU_VERSION "0.5.1" #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ @@ -610,7 +604,6 @@ static int vidioc_querycap(struct file *file, void *priv, { strcpy(cap->driver, "viu"); strcpy(cap->card, "viu"); - cap->version = VIU_VERSION; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OVERLAY | @@ -1684,3 +1677,4 @@ module_exit(viu_exit); MODULE_DESCRIPTION("Freescale Video-In(VIU)"); MODULE_AUTHOR("Hongjun Chen"); MODULE_LICENSE("GPL"); +MODULE_VERSION(VIU_VERSION); diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig index 34ae2c299799c350f255e0988bc4325d4dedf124..43d9a20caebc3f6439693e0833530e247c4b94ee 100644 --- a/drivers/media/video/gspca/Kconfig +++ b/drivers/media/video/gspca/Kconfig @@ -179,6 +179,16 @@ config USB_GSPCA_PAC7311 To compile this driver as a module, choose M here: the module will be called gspca_pac7311. +config USB_GSPCA_SE401 + tristate "SE401 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the + Endpoints (formerly known as AOX) se401 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_se401. + config USB_GSPCA_SN9C2028 tristate "SONIX Dual-Mode USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile index 802fbe1bff4a009f2787f749771f4e57ce9ccda9..d6364a86333ab8382d5ab11f0f360087a927ad39 100644 --- a/drivers/media/video/gspca/Makefile +++ b/drivers/media/video/gspca/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_USB_GSPCA_OV534_9) += gspca_ov534_9.o obj-$(CONFIG_USB_GSPCA_PAC207) += gspca_pac207.o obj-$(CONFIG_USB_GSPCA_PAC7302) += gspca_pac7302.o obj-$(CONFIG_USB_GSPCA_PAC7311) += gspca_pac7311.o +obj-$(CONFIG_USB_GSPCA_SE401) += gspca_se401.o obj-$(CONFIG_USB_GSPCA_SN9C2028) += gspca_sn9c2028.o obj-$(CONFIG_USB_GSPCA_SN9C20X) += gspca_sn9c20x.o obj-$(CONFIG_USB_GSPCA_SONIXB) += gspca_sonixb.o @@ -58,6 +59,7 @@ gspca_ov534_9-objs := ov534_9.o gspca_pac207-objs := pac207.o gspca_pac7302-objs := pac7302.o gspca_pac7311-objs := pac7311.o +gspca_se401-objs := se401.o gspca_sn9c2028-objs := sn9c2028.o gspca_sn9c20x-objs := sn9c20x.o gspca_sonixb-objs := sonixb.o diff --git a/drivers/media/video/gspca/gl860/gl860.h b/drivers/media/video/gspca/gl860/gl860.h index 49ad4acbf602663c0963d09e420aaf8a1cabf149..0330a0293b9ca58aed0a9e6a9461f5451b7151a4 100644 --- a/drivers/media/video/gspca/gl860/gl860.h +++ b/drivers/media/video/gspca/gl860/gl860.h @@ -18,7 +18,6 @@ */ #ifndef GL860_DEV_H #define GL860_DEV_H -#include #include "gspca.h" diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 08ce9948d99b28f28e0800fc9ffdeaf18d2d8551..5da4879f47f2c3e01342479add75a04332e48fa8 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -24,7 +24,6 @@ #define MODULE_NAME "gspca" #include -#include #include #include #include @@ -51,11 +50,12 @@ #error "DEF_NURBS too big" #endif +#define DRIVER_VERSION_NUMBER "2.13.0" + MODULE_AUTHOR("Jean-François Moine "); MODULE_DESCRIPTION("GSPCA USB Camera Driver"); MODULE_LICENSE("GPL"); - -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 13, 0) +MODULE_VERSION(DRIVER_VERSION_NUMBER); #ifdef GSPCA_DEBUG int gspca_debug = D_ERR | D_PROBE; @@ -443,8 +443,11 @@ void gspca_frame_add(struct gspca_dev *gspca_dev, } else { switch (gspca_dev->last_packet_type) { case DISCARD_PACKET: - if (packet_type == LAST_PACKET) + if (packet_type == LAST_PACKET) { gspca_dev->last_packet_type = packet_type; + gspca_dev->image = NULL; + gspca_dev->image_len = 0; + } return; case LAST_PACKET: return; @@ -1278,10 +1281,10 @@ static int vidioc_querycap(struct file *file, void *priv, ret = -ENODEV; goto out; } - strncpy((char *) cap->driver, gspca_dev->sd_desc->name, + strlcpy((char *) cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver); if (gspca_dev->dev->product != NULL) { - strncpy((char *) cap->card, gspca_dev->dev->product, + strlcpy((char *) cap->card, gspca_dev->dev->product, sizeof cap->card); } else { snprintf((char *) cap->card, sizeof cap->card, @@ -1291,7 +1294,6 @@ static int vidioc_querycap(struct file *file, void *priv, } usb_make_path(gspca_dev->dev, (char *) cap->bus_info, sizeof(cap->bus_info)); - cap->version = DRIVER_VERSION_NUMBER; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; @@ -1460,7 +1462,7 @@ static int vidioc_enum_input(struct file *file, void *priv, return -EINVAL; input->type = V4L2_INPUT_TYPE_CAMERA; input->status = gspca_dev->cam.input_flags; - strncpy(input->name, gspca_dev->sd_desc->name, + strlcpy(input->name, gspca_dev->sd_desc->name, sizeof input->name); return 0; } @@ -2478,10 +2480,7 @@ EXPORT_SYMBOL(gspca_auto_gain_n_exposure); /* -- module insert / remove -- */ static int __init gspca_init(void) { - info("v%d.%d.%d registered", - (DRIVER_VERSION_NUMBER >> 16) & 0xff, - (DRIVER_VERSION_NUMBER >> 8) & 0xff, - DRIVER_VERSION_NUMBER & 0xff); + info("v" DRIVER_VERSION_NUMBER " registered"); return 0; } static void __exit gspca_exit(void) diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index 057e287b9152a78fea793bdefa8ec6d26b699085..0800433b209287c45c9f4672a41f20e99b43adfe 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -134,6 +134,7 @@ enum sensors { SEN_OV7670, SEN_OV76BE, SEN_OV8610, + SEN_OV9600, }; /* Note this is a bit of a hack, but the w9968cf driver needs the code for all @@ -340,6 +341,10 @@ static const unsigned ctrl_dis[] = { (1 << EXPOSURE) | (1 << AUTOGAIN) | (1 << FREQ), +[SEN_OV9600] = ((1 << NCTRL) - 1) /* no control */ + ^ ((1 << EXPOSURE) /* but exposure */ + | (1 << AUTOGAIN)), /* and autogain */ + }; static const struct v4l2_pix_format ov519_vga_mode[] = { @@ -525,6 +530,17 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = { .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, }; +static const struct v4l2_pix_format ovfx2_ov9600_mode[] = { + {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 1280, + .sizeimage = 1280 * 1024, + .colorspace = V4L2_COLORSPACE_SRGB}, +}; /* Registers common to OV511 / OV518 */ #define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */ @@ -1807,6 +1823,22 @@ static const struct ov_i2c_regvals norm_7660[] = { | OV7670_COM8_AEC}, {0xa1, 0xc8} }; +static const struct ov_i2c_regvals norm_9600[] = { + {0x12, 0x80}, + {0x0c, 0x28}, + {0x11, 0x80}, + {0x13, 0xb5}, + {0x14, 0x3e}, + {0x1b, 0x04}, + {0x24, 0xb0}, + {0x25, 0x90}, + {0x26, 0x94}, + {0x35, 0x90}, + {0x37, 0x07}, + {0x38, 0x08}, + {0x01, 0x8e}, + {0x02, 0x85} +}; /* 7670. Defaults taken from OmniVision provided data, * as provided by Jonathan Corbet of OLPC */ @@ -2400,9 +2432,12 @@ static int ov518_i2c_r(struct sd *sd, u8 reg) /* Initiate 2-byte write cycle */ reg_w(sd, R518_I2C_CTL, 0x03); + reg_r8(sd, R518_I2C_CTL); /* Initiate 2-byte read cycle */ reg_w(sd, R518_I2C_CTL, 0x05); + reg_r8(sd, R518_I2C_CTL); + value = reg_r(sd, R51x_I2C_DATA); PDEBUG(D_USBI, "ov518_i2c_r %02x %02x", reg, value); return value; @@ -2686,7 +2721,7 @@ static void write_i2c_regvals(struct sd *sd, * ***************************************************************************/ -/* This initializes the OV2x10 / OV3610 / OV3620 */ +/* This initializes the OV2x10 / OV3610 / OV3620 / OV9600 */ static void ov_hires_configure(struct sd *sd) { int high, low; @@ -2702,19 +2737,32 @@ static void ov_hires_configure(struct sd *sd) high = i2c_r(sd, 0x0a); low = i2c_r(sd, 0x0b); /* info("%x, %x", high, low); */ - if (high == 0x96 && low == 0x40) { - PDEBUG(D_PROBE, "Sensor is an OV2610"); - sd->sensor = SEN_OV2610; - } else if (high == 0x96 && low == 0x41) { - PDEBUG(D_PROBE, "Sensor is an OV2610AE"); - sd->sensor = SEN_OV2610AE; - } else if (high == 0x36 && (low & 0x0f) == 0x00) { - PDEBUG(D_PROBE, "Sensor is an OV3610"); - sd->sensor = SEN_OV3610; - } else { - err("Error unknown sensor type: %02x%02x", - high, low); + switch (high) { + case 0x96: + switch (low) { + case 0x40: + PDEBUG(D_PROBE, "Sensor is a OV2610"); + sd->sensor = SEN_OV2610; + return; + case 0x41: + PDEBUG(D_PROBE, "Sensor is a OV2610AE"); + sd->sensor = SEN_OV2610AE; + return; + case 0xb1: + PDEBUG(D_PROBE, "Sensor is a OV9600"); + sd->sensor = SEN_OV9600; + return; + } + break; + case 0x36: + if ((low & 0x0f) == 0x00) { + PDEBUG(D_PROBE, "Sensor is a OV3610"); + sd->sensor = SEN_OV3610; + return; + } + break; } + err("Error unknown sensor type: %02x%02x", high, low); } /* This initializes the OV8110, OV8610 sensor. The OV8110 uses @@ -3400,6 +3448,10 @@ static int sd_init(struct gspca_dev *gspca_dev) cam->cam_mode = ovfx2_ov3610_mode; cam->nmodes = ARRAY_SIZE(ovfx2_ov3610_mode); break; + case SEN_OV9600: + cam->cam_mode = ovfx2_ov9600_mode; + cam->nmodes = ARRAY_SIZE(ovfx2_ov9600_mode); + break; default: if (sd->sif) { cam->cam_mode = ov519_sif_mode; @@ -3497,6 +3549,12 @@ static int sd_init(struct gspca_dev *gspca_dev) case SEN_OV8610: write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)); break; + case SEN_OV9600: + write_i2c_regvals(sd, norm_9600, ARRAY_SIZE(norm_9600)); + + /* enable autoexpo */ +/* i2c_w_mask(sd, 0x13, 0x05, 0x05); */ + break; } return gspca_dev->usb_err; error: @@ -4085,6 +4143,33 @@ static void mode_init_ov_sensor_regs(struct sd *sd) i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */ break; + case SEN_OV9600: { + const struct ov_i2c_regvals *vals; + static const struct ov_i2c_regvals sxga_15[] = { + {0x11, 0x80}, {0x14, 0x3e}, {0x24, 0x85}, {0x25, 0x75} + }; + static const struct ov_i2c_regvals sxga_7_5[] = { + {0x11, 0x81}, {0x14, 0x3e}, {0x24, 0x85}, {0x25, 0x75} + }; + static const struct ov_i2c_regvals vga_30[] = { + {0x11, 0x81}, {0x14, 0x7e}, {0x24, 0x70}, {0x25, 0x60} + }; + static const struct ov_i2c_regvals vga_15[] = { + {0x11, 0x83}, {0x14, 0x3e}, {0x24, 0x80}, {0x25, 0x70} + }; + + /* frame rates: + * 15fps / 7.5 fps for 1280x1024 + * 30fps / 15fps for 640x480 + */ + i2c_w_mask(sd, 0x12, qvga ? 0x40 : 0x00, 0x40); + if (qvga) + vals = sd->frame_rate < 30 ? vga_15 : vga_30; + else + vals = sd->frame_rate < 15 ? sxga_7_5 : sxga_15; + write_i2c_regvals(sd, vals, ARRAY_SIZE(sxga_15)); + return; + } default: return; } @@ -4120,6 +4205,7 @@ static void set_ov_sensor_window(struct sd *sd) case SEN_OV2610AE: case SEN_OV3610: case SEN_OV7670: + case SEN_OV9600: mode_init_ov_sensor_regs(sd); return; case SEN_OV7660: @@ -4920,7 +5006,8 @@ static const struct sd_desc sd_desc = { static const struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF }, {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x041e, 0x405f), + .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, {USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x041e, 0x4064), diff --git a/drivers/media/video/gspca/se401.c b/drivers/media/video/gspca/se401.c new file mode 100644 index 0000000000000000000000000000000000000000..4c283c24c752bd7dffa26d2a67db71b6c32ba251 --- /dev/null +++ b/drivers/media/video/gspca/se401.c @@ -0,0 +1,774 @@ +/* + * GSPCA Endpoints (formerly known as AOX) se401 USB Camera sub Driver + * + * Copyright (C) 2011 Hans de Goede + * + * Based on the v4l1 se401 driver which is: + * + * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org) + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define MODULE_NAME "se401" + +#define BULK_SIZE 4096 +#define PACKET_SIZE 1024 +#define READ_REQ_SIZE 64 +#define MAX_MODES ((READ_REQ_SIZE - 6) / 4) +/* The se401 compression algorithm uses a fixed quant factor, which + can be configured by setting the high nibble of the SE401_OPERATINGMODE + feature. This needs to exactly match what is in libv4l! */ +#define SE401_QUANT_FACT 8 + +#include +#include +#include "gspca.h" +#include "se401.h" + +MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("Endpoints se401"); +MODULE_LICENSE("GPL"); + +/* controls */ +enum e_ctrl { + BRIGHTNESS, + GAIN, + EXPOSURE, + FREQ, + NCTRL /* number of controls */ +}; + +/* exposure change state machine states */ +enum { + EXPO_CHANGED, + EXPO_DROP_FRAME, + EXPO_NO_CHANGE, +}; + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + struct gspca_ctrl ctrls[NCTRL]; + struct v4l2_pix_format fmts[MAX_MODES]; + int pixels_read; + int packet_read; + u8 packet[PACKET_SIZE]; + u8 restart_stream; + u8 button_state; + u8 resetlevel; + u8 resetlevel_frame_count; + int resetlevel_adjust_dir; + int expo_change_state; +}; + +static void setbrightness(struct gspca_dev *gspca_dev); +static void setgain(struct gspca_dev *gspca_dev); +static void setexposure(struct gspca_dev *gspca_dev); + +static const struct ctrl sd_ctrls[NCTRL] = { +[BRIGHTNESS] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 15, + }, + .set_control = setbrightness + }, +[GAIN] = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 50, /* Really 63 but > 50 is not pretty */ + .step = 1, + .default_value = 25, + }, + .set_control = setgain + }, +[EXPOSURE] = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 32767, + .step = 1, + .default_value = 15000, + }, + .set_control = setexposure + }, +[FREQ] = { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light frequency filter", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + .set_control = setexposure + }, +}; + +static void se401_write_req(struct gspca_dev *gspca_dev, u16 req, u16 value, + int silent) +{ + int err; + + if (gspca_dev->usb_err < 0) + return; + + err = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, 0, NULL, 0, 1000); + if (err < 0) { + if (!silent) + err("write req failed req %#04x val %#04x error %d", + req, value, err); + gspca_dev->usb_err = err; + } +} + +static void se401_read_req(struct gspca_dev *gspca_dev, u16 req, int silent) +{ + int err; + + if (gspca_dev->usb_err < 0) + return; + + if (USB_BUF_SZ < READ_REQ_SIZE) { + err("USB_BUF_SZ too small!!"); + gspca_dev->usb_err = -ENOBUFS; + return; + } + + err = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, 0, gspca_dev->usb_buf, READ_REQ_SIZE, 1000); + if (err < 0) { + if (!silent) + err("read req failed req %#04x error %d", req, err); + gspca_dev->usb_err = err; + } +} + +static void se401_set_feature(struct gspca_dev *gspca_dev, + u16 selector, u16 param) +{ + int err; + + if (gspca_dev->usb_err < 0) + return; + + err = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + SE401_REQ_SET_EXT_FEATURE, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + param, selector, NULL, 0, 1000); + if (err < 0) { + err("set feature failed sel %#04x param %#04x error %d", + selector, param, err); + gspca_dev->usb_err = err; + } +} + +static int se401_get_feature(struct gspca_dev *gspca_dev, u16 selector) +{ + int err; + + if (gspca_dev->usb_err < 0) + return gspca_dev->usb_err; + + if (USB_BUF_SZ < 2) { + err("USB_BUF_SZ too small!!"); + gspca_dev->usb_err = -ENOBUFS; + return gspca_dev->usb_err; + } + + err = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + SE401_REQ_GET_EXT_FEATURE, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, selector, gspca_dev->usb_buf, 2, 1000); + if (err < 0) { + err("get feature failed sel %#04x error %d", selector, err); + gspca_dev->usb_err = err; + return err; + } + return gspca_dev->usb_buf[0] | (gspca_dev->usb_buf[1] << 8); +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS)) + return; + + /* HDG: this does not seem to do anything on my cam */ + se401_write_req(gspca_dev, SE401_REQ_SET_BRT, + sd->ctrls[BRIGHTNESS].val, 0); +} + +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u16 gain = 63 - sd->ctrls[GAIN].val; + + /* red color gain */ + se401_set_feature(gspca_dev, HV7131_REG_ARCG, gain); + /* green color gain */ + se401_set_feature(gspca_dev, HV7131_REG_AGCG, gain); + /* blue color gain */ + se401_set_feature(gspca_dev, HV7131_REG_ABCG, gain); +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int integration = sd->ctrls[EXPOSURE].val << 6; + u8 expose_h, expose_m, expose_l; + + /* Do this before the set_feature calls, for proper timing wrt + the interrupt driven pkt_scan. Note we may still race but that + is not a big issue, the expo change state machine is merely for + avoiding underexposed frames getting send out, if one sneaks + through so be it */ + sd->expo_change_state = EXPO_CHANGED; + + if (sd->ctrls[FREQ].val == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) + integration = integration - integration % 106667; + if (sd->ctrls[FREQ].val == V4L2_CID_POWER_LINE_FREQUENCY_60HZ) + integration = integration - integration % 88889; + + expose_h = (integration >> 16); + expose_m = (integration >> 8); + expose_l = integration; + + /* integration time low */ + se401_set_feature(gspca_dev, HV7131_REG_TITL, expose_l); + /* integration time mid */ + se401_set_feature(gspca_dev, HV7131_REG_TITM, expose_m); + /* integration time high */ + se401_set_feature(gspca_dev, HV7131_REG_TITU, expose_h); +} + +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *)gspca_dev; + struct cam *cam = &gspca_dev->cam; + u8 *cd = gspca_dev->usb_buf; + int i, j, n; + int widths[MAX_MODES], heights[MAX_MODES]; + + /* Read the camera descriptor */ + se401_read_req(gspca_dev, SE401_REQ_GET_CAMERA_DESCRIPTOR, 1); + if (gspca_dev->usb_err) { + /* Sometimes after being idle for a while the se401 won't + respond and needs a good kicking */ + usb_reset_device(gspca_dev->dev); + gspca_dev->usb_err = 0; + se401_read_req(gspca_dev, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0); + } + + /* Some cameras start with their LED on */ + se401_write_req(gspca_dev, SE401_REQ_LED_CONTROL, 0, 0); + if (gspca_dev->usb_err) + return gspca_dev->usb_err; + + if (cd[1] != 0x41) { + err("Wrong descriptor type"); + return -ENODEV; + } + + if (!(cd[2] & SE401_FORMAT_BAYER)) { + err("Bayer format not supported!"); + return -ENODEV; + } + + if (cd[3]) + info("ExtraFeatures: %d", cd[3]); + + n = cd[4] | (cd[5] << 8); + if (n > MAX_MODES) { + err("Too many frame sizes"); + return -ENODEV; + } + + for (i = 0; i < n ; i++) { + widths[i] = cd[6 + i * 4 + 0] | (cd[6 + i * 4 + 1] << 8); + heights[i] = cd[6 + i * 4 + 2] | (cd[6 + i * 4 + 3] << 8); + } + + for (i = 0; i < n ; i++) { + sd->fmts[i].width = widths[i]; + sd->fmts[i].height = heights[i]; + sd->fmts[i].field = V4L2_FIELD_NONE; + sd->fmts[i].colorspace = V4L2_COLORSPACE_SRGB; + sd->fmts[i].priv = 1; + + /* janggu compression only works for 1/4th or 1/16th res */ + for (j = 0; j < n; j++) { + if (widths[j] / 2 == widths[i] && + heights[j] / 2 == heights[i]) { + sd->fmts[i].priv = 2; + break; + } + } + /* 1/16th if available too is better then 1/4th, because + we then use a larger area of the sensor */ + for (j = 0; j < n; j++) { + if (widths[j] / 4 == widths[i] && + heights[j] / 4 == heights[i]) { + sd->fmts[i].priv = 4; + break; + } + } + + if (sd->fmts[i].priv == 1) { + /* Not a 1/4th or 1/16th res, use bayer */ + sd->fmts[i].pixelformat = V4L2_PIX_FMT_SBGGR8; + sd->fmts[i].bytesperline = widths[i]; + sd->fmts[i].sizeimage = widths[i] * heights[i]; + info("Frame size: %dx%d bayer", widths[i], heights[i]); + } else { + /* Found a match use janggu compression */ + sd->fmts[i].pixelformat = V4L2_PIX_FMT_SE401; + sd->fmts[i].bytesperline = 0; + sd->fmts[i].sizeimage = widths[i] * heights[i] * 3; + info("Frame size: %dx%d 1/%dth janggu", + widths[i], heights[i], + sd->fmts[i].priv * sd->fmts[i].priv); + } + } + + cam->cam_mode = sd->fmts; + cam->nmodes = n; + cam->bulk = 1; + cam->bulk_size = BULK_SIZE; + cam->bulk_nurbs = 4; + cam->ctrls = sd->ctrls; + gspca_dev->nbalt = 1; /* Ignore the bogus isoc alt settings */ + sd->resetlevel = 0x2d; /* Set initial resetlevel */ + + /* See if the camera supports brightness */ + se401_read_req(gspca_dev, SE401_REQ_GET_BRT, 1); + if (gspca_dev->usb_err) { + gspca_dev->ctrl_dis = (1 << BRIGHTNESS); + gspca_dev->usb_err = 0; + } + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + return 0; +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + int mult = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + int mode = 0; + + se401_write_req(gspca_dev, SE401_REQ_CAMERA_POWER, 1, 1); + if (gspca_dev->usb_err) { + /* Sometimes after being idle for a while the se401 won't + respond and needs a good kicking */ + usb_reset_device(gspca_dev->dev); + gspca_dev->usb_err = 0; + se401_write_req(gspca_dev, SE401_REQ_CAMERA_POWER, 1, 0); + } + se401_write_req(gspca_dev, SE401_REQ_LED_CONTROL, 1, 0); + + se401_set_feature(gspca_dev, HV7131_REG_MODE_B, 0x05); + + /* set size + mode */ + se401_write_req(gspca_dev, SE401_REQ_SET_WIDTH, + gspca_dev->width * mult, 0); + se401_write_req(gspca_dev, SE401_REQ_SET_HEIGHT, + gspca_dev->height * mult, 0); + /* + * HDG: disabled this as it does not seem to do anything + * se401_write_req(gspca_dev, SE401_REQ_SET_OUTPUT_MODE, + * SE401_FORMAT_BAYER, 0); + */ + + switch (mult) { + case 1: /* Raw bayer */ + mode = 0x03; break; + case 2: /* 1/4th janggu */ + mode = SE401_QUANT_FACT << 4; break; + case 4: /* 1/16th janggu */ + mode = (SE401_QUANT_FACT << 4) | 0x02; break; + } + se401_set_feature(gspca_dev, SE401_OPERATINGMODE, mode); + + setbrightness(gspca_dev); + setgain(gspca_dev); + setexposure(gspca_dev); + se401_set_feature(gspca_dev, HV7131_REG_ARLV, sd->resetlevel); + + sd->packet_read = 0; + sd->pixels_read = 0; + sd->restart_stream = 0; + sd->resetlevel_frame_count = 0; + sd->resetlevel_adjust_dir = 0; + sd->expo_change_state = EXPO_NO_CHANGE; + + se401_write_req(gspca_dev, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, 0); + + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + se401_write_req(gspca_dev, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, 0); + se401_write_req(gspca_dev, SE401_REQ_LED_CONTROL, 0, 0); + se401_write_req(gspca_dev, SE401_REQ_CAMERA_POWER, 0, 0); +} + +static void sd_dq_callback(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + unsigned int ahrc, alrc; + int oldreset, adjust_dir; + + /* Restart the stream if requested do so by pkt_scan */ + if (sd->restart_stream) { + sd_stopN(gspca_dev); + sd_start(gspca_dev); + sd->restart_stream = 0; + } + + /* Automatically adjust sensor reset level + Hyundai have some really nice docs about this and other sensor + related stuff on their homepage: www.hei.co.kr */ + sd->resetlevel_frame_count++; + if (sd->resetlevel_frame_count < 20) + return; + + /* For some reason this normally read-only register doesn't get reset + to zero after reading them just once... */ + se401_get_feature(gspca_dev, HV7131_REG_HIREFNOH); + se401_get_feature(gspca_dev, HV7131_REG_HIREFNOL); + se401_get_feature(gspca_dev, HV7131_REG_LOREFNOH); + se401_get_feature(gspca_dev, HV7131_REG_LOREFNOL); + ahrc = 256*se401_get_feature(gspca_dev, HV7131_REG_HIREFNOH) + + se401_get_feature(gspca_dev, HV7131_REG_HIREFNOL); + alrc = 256*se401_get_feature(gspca_dev, HV7131_REG_LOREFNOH) + + se401_get_feature(gspca_dev, HV7131_REG_LOREFNOL); + + /* Not an exact science, but it seems to work pretty well... */ + oldreset = sd->resetlevel; + if (alrc > 10) { + while (alrc >= 10 && sd->resetlevel < 63) { + sd->resetlevel++; + alrc /= 2; + } + } else if (ahrc > 20) { + while (ahrc >= 20 && sd->resetlevel > 0) { + sd->resetlevel--; + ahrc /= 2; + } + } + /* Detect ping-pong-ing and halve adjustment to avoid overshoot */ + if (sd->resetlevel > oldreset) + adjust_dir = 1; + else + adjust_dir = -1; + if (sd->resetlevel_adjust_dir && + sd->resetlevel_adjust_dir != adjust_dir) + sd->resetlevel = oldreset + (sd->resetlevel - oldreset) / 2; + + if (sd->resetlevel != oldreset) { + sd->resetlevel_adjust_dir = adjust_dir; + se401_set_feature(gspca_dev, HV7131_REG_ARLV, sd->resetlevel); + } + + sd->resetlevel_frame_count = 0; +} + +static void sd_complete_frame(struct gspca_dev *gspca_dev, u8 *data, int len) +{ + struct sd *sd = (struct sd *)gspca_dev; + + switch (sd->expo_change_state) { + case EXPO_CHANGED: + /* The exposure was changed while this frame + was being send, so this frame is ok */ + sd->expo_change_state = EXPO_DROP_FRAME; + break; + case EXPO_DROP_FRAME: + /* The exposure was changed while this frame + was being captured, drop it! */ + gspca_dev->last_packet_type = DISCARD_PACKET; + sd->expo_change_state = EXPO_NO_CHANGE; + break; + case EXPO_NO_CHANGE: + break; + } + gspca_frame_add(gspca_dev, LAST_PACKET, data, len); +} + +static void sd_pkt_scan_janggu(struct gspca_dev *gspca_dev, u8 *data, int len) +{ + struct sd *sd = (struct sd *)gspca_dev; + int imagesize = gspca_dev->width * gspca_dev->height; + int i, plen, bits, pixels, info, count; + + if (sd->restart_stream) + return; + + /* Sometimes a 1024 bytes garbage bulk packet is send between frames */ + if (gspca_dev->last_packet_type == LAST_PACKET && len == 1024) { + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + } + + i = 0; + while (i < len) { + /* Read header if not already be present from prev bulk pkt */ + if (sd->packet_read < 4) { + count = 4 - sd->packet_read; + if (count > len - i) + count = len - i; + memcpy(&sd->packet[sd->packet_read], &data[i], count); + sd->packet_read += count; + i += count; + if (sd->packet_read < 4) + break; + } + bits = sd->packet[3] + (sd->packet[2] << 8); + pixels = sd->packet[1] + ((sd->packet[0] & 0x3f) << 8); + info = (sd->packet[0] & 0xc0) >> 6; + plen = ((bits + 47) >> 4) << 1; + /* Sanity checks */ + if (plen > 1024) { + err("invalid packet len %d restarting stream", plen); + goto error; + } + if (info == 3) { + err("unknown frame info value restarting stream"); + goto error; + } + + /* Read (remainder of) packet contents */ + count = plen - sd->packet_read; + if (count > len - i) + count = len - i; + memcpy(&sd->packet[sd->packet_read], &data[i], count); + sd->packet_read += count; + i += count; + if (sd->packet_read < plen) + break; + + sd->pixels_read += pixels; + sd->packet_read = 0; + + switch (info) { + case 0: /* Frame data */ + gspca_frame_add(gspca_dev, INTER_PACKET, sd->packet, + plen); + break; + case 1: /* EOF */ + if (sd->pixels_read != imagesize) { + err("frame size %d expected %d", + sd->pixels_read, imagesize); + goto error; + } + sd_complete_frame(gspca_dev, sd->packet, plen); + return; /* Discard the rest of the bulk packet !! */ + case 2: /* SOF */ + gspca_frame_add(gspca_dev, FIRST_PACKET, sd->packet, + plen); + sd->pixels_read = pixels; + break; + } + } + return; + +error: + sd->restart_stream = 1; + /* Give userspace a 0 bytes frame, so our dq callback gets + called and it can restart the stream */ + gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); +} + +static void sd_pkt_scan_bayer(struct gspca_dev *gspca_dev, u8 *data, int len) +{ + struct cam *cam = &gspca_dev->cam; + int imagesize = cam->cam_mode[gspca_dev->curr_mode].sizeimage; + + if (gspca_dev->image_len == 0) { + gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); + return; + } + + if (gspca_dev->image_len + len >= imagesize) { + sd_complete_frame(gspca_dev, data, len); + return; + } + + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, int len) +{ + int mult = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + + if (len == 0) + return; + + if (mult == 1) /* mult == 1 means raw bayer */ + sd_pkt_scan_bayer(gspca_dev, data, len); + else + sd_pkt_scan_janggu(gspca_dev, data, len); +} + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (menu->index) { + case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: + strcpy((char *) menu->name, "NoFliker"); + return 0; + case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: + strcpy((char *) menu->name, "50 Hz"); + return 0; + case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: + strcpy((char *) menu->name, "60 Hz"); + return 0; + } + break; + } + return -EINVAL; +} + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) +static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, int len) +{ + struct sd *sd = (struct sd *)gspca_dev; + u8 state; + + if (len != 2) + return -EINVAL; + + switch (data[0]) { + case 0: + case 1: + state = data[0]; + break; + default: + return -EINVAL; + } + if (sd->button_state != state) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, state); + input_sync(gspca_dev->input_dev); + sd->button_state = state; + } + + return 0; +} +#endif + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .dq_callback = sd_dq_callback, + .pkt_scan = sd_pkt_scan, + .querymenu = sd_querymenu, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .int_pkt_scan = sd_int_pkt_scan, +#endif +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x03e8, 0x0004)}, /* Endpoints/Aox SE401 */ + {USB_DEVICE(0x0471, 0x030b)}, /* Philips PCVC665K */ + {USB_DEVICE(0x047d, 0x5001)}, /* Kensington 67014 */ + {USB_DEVICE(0x047d, 0x5002)}, /* Kensington 6701(5/7) */ + {USB_DEVICE(0x047d, 0x5003)}, /* Kensington 67016 */ + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static int sd_pre_reset(struct usb_interface *intf) +{ + return 0; +} + +static int sd_post_reset(struct usb_interface *intf) +{ + return 0; +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif + .pre_reset = sd_pre_reset, + .post_reset = sd_post_reset, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/se401.h b/drivers/media/video/gspca/se401.h new file mode 100644 index 0000000000000000000000000000000000000000..96d8ebf3cf595622d2547344b078586b63c3a19e --- /dev/null +++ b/drivers/media/video/gspca/se401.h @@ -0,0 +1,90 @@ +/* + * GSPCA Endpoints (formerly known as AOX) se401 USB Camera sub Driver + * + * Copyright (C) 2011 Hans de Goede + * + * Based on the v4l1 se401 driver which is: + * + * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org) + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define SE401_REQ_GET_CAMERA_DESCRIPTOR 0x06 +#define SE401_REQ_START_CONTINUOUS_CAPTURE 0x41 +#define SE401_REQ_STOP_CONTINUOUS_CAPTURE 0x42 +#define SE401_REQ_CAPTURE_FRAME 0x43 +#define SE401_REQ_GET_BRT 0x44 +#define SE401_REQ_SET_BRT 0x45 +#define SE401_REQ_GET_WIDTH 0x4c +#define SE401_REQ_SET_WIDTH 0x4d +#define SE401_REQ_GET_HEIGHT 0x4e +#define SE401_REQ_SET_HEIGHT 0x4f +#define SE401_REQ_GET_OUTPUT_MODE 0x50 +#define SE401_REQ_SET_OUTPUT_MODE 0x51 +#define SE401_REQ_GET_EXT_FEATURE 0x52 +#define SE401_REQ_SET_EXT_FEATURE 0x53 +#define SE401_REQ_CAMERA_POWER 0x56 +#define SE401_REQ_LED_CONTROL 0x57 +#define SE401_REQ_BIOS 0xff + +#define SE401_BIOS_READ 0x07 + +#define SE401_FORMAT_BAYER 0x40 + +/* Hyundai hv7131b registers + 7121 and 7141 should be the same (haven't really checked...) */ +/* Mode registers: */ +#define HV7131_REG_MODE_A 0x00 +#define HV7131_REG_MODE_B 0x01 +#define HV7131_REG_MODE_C 0x02 +/* Frame registers: */ +#define HV7131_REG_FRSU 0x10 +#define HV7131_REG_FRSL 0x11 +#define HV7131_REG_FCSU 0x12 +#define HV7131_REG_FCSL 0x13 +#define HV7131_REG_FWHU 0x14 +#define HV7131_REG_FWHL 0x15 +#define HV7131_REG_FWWU 0x16 +#define HV7131_REG_FWWL 0x17 +/* Timing registers: */ +#define HV7131_REG_THBU 0x20 +#define HV7131_REG_THBL 0x21 +#define HV7131_REG_TVBU 0x22 +#define HV7131_REG_TVBL 0x23 +#define HV7131_REG_TITU 0x25 +#define HV7131_REG_TITM 0x26 +#define HV7131_REG_TITL 0x27 +#define HV7131_REG_TMCD 0x28 +/* Adjust Registers: */ +#define HV7131_REG_ARLV 0x30 +#define HV7131_REG_ARCG 0x31 +#define HV7131_REG_AGCG 0x32 +#define HV7131_REG_ABCG 0x33 +#define HV7131_REG_APBV 0x34 +#define HV7131_REG_ASLP 0x54 +/* Offset Registers: */ +#define HV7131_REG_OFSR 0x50 +#define HV7131_REG_OFSG 0x51 +#define HV7131_REG_OFSB 0x52 +/* REset level statistics registers: */ +#define HV7131_REG_LOREFNOH 0x57 +#define HV7131_REG_LOREFNOL 0x58 +#define HV7131_REG_HIREFNOH 0x59 +#define HV7131_REG_HIREFNOL 0x5a + +/* se401 registers */ +#define SE401_OPERATINGMODE 0x2000 diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index b089c0d3ee9f96dc7b2de6f770105efe35db1503..6ec232902183ebb7b2dc4c7afe93010b9c1cd791 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c @@ -247,7 +247,6 @@ static const struct cmd spca504A_clicksmart420_init_data[] = { {0x30, 0x0004, 0x000a}, {0xb0, 0x0001, 0x0000}, - {0xa1, 0x0080, 0x0001}, {0x30, 0x0049, 0x0000}, {0x30, 0x0060, 0x0005}, @@ -256,8 +255,6 @@ static const struct cmd spca504A_clicksmart420_init_data[] = { {0x00, 0x0000, 0x2000}, {0x00, 0x0013, 0x2301}, {0x00, 0x0003, 0x2000}, - {0x00, 0x0000, 0x2000}, - }; /* clicksmart 420 open data ? */ diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c index 7e762d55109915d52e0d7306e554f2210d2f6461..d1d733b9359b41e9f012a6d6b651d2f4b2597a3b 100644 --- a/drivers/media/video/gspca/t613.c +++ b/drivers/media/video/gspca/t613.c @@ -1387,7 +1387,7 @@ static int sd_querymenu(struct gspca_dev *gspca_dev, return 0; case V4L2_CID_EFFECTS: if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) { - strncpy((char *) menu->name, + strlcpy((char *) menu->name, effects_control[menu->index], sizeof menu->name); return 0; diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c index 5f1db46beb4e18031a0342f9f6e48cc241106303..441dacf642bb090fc270676403868f778d3b34e3 100644 --- a/drivers/media/video/hdpvr/hdpvr-core.c +++ b/drivers/media/video/hdpvr/hdpvr-core.c @@ -474,5 +474,6 @@ module_init(hdpvr_init); module_exit(hdpvr_exit); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.2.1"); MODULE_AUTHOR("Janne Grunau"); MODULE_DESCRIPTION("Hauppauge HD PVR driver"); diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c index 514aea76eaa5b68b30acf66b0ce4fd4446421fb5..087f7c08cb851ee50485dd2a50e80f30d9a82674 100644 --- a/drivers/media/video/hdpvr/hdpvr-video.c +++ b/drivers/media/video/hdpvr/hdpvr-video.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -574,7 +573,6 @@ static int vidioc_querycap(struct file *file, void *priv, strcpy(cap->driver, "hdpvr"); strcpy(cap->card, "Hauppauge HD PVR"); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->version = HDPVR_VERSION; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE; diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/video/hdpvr/hdpvr.h index 072f23c570f343388e11582d504e07e7ae38ab74..d6439db1d18beb1d10b745a303149316016236e6 100644 --- a/drivers/media/video/hdpvr/hdpvr.h +++ b/drivers/media/video/hdpvr/hdpvr.h @@ -18,12 +18,6 @@ #include #include -#define HDPVR_MAJOR_VERSION 0 -#define HDPVR_MINOR_VERSION 2 -#define HDPVR_RELEASE 0 -#define HDPVR_VERSION \ - KERNEL_VERSION(HDPVR_MAJOR_VERSION, HDPVR_MINOR_VERSION, HDPVR_RELEASE) - #define HDPVR_MAX 8 #define HDPVR_I2C_MAX_SIZE 128 diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 84bdf0f42a8eb81a3b4016869547e24cb2d46202..8f9cc17b518eaaf6320e092d0a667d8d4876e586 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -36,7 +36,6 @@ * using information provided by Jiun-Kuei Jung @ AVerMedia. */ -#include #include #include #include diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index a7f54b010a5c705e1fd0320b1f9aaaaf8ec8f7aa..38f052257f4620498d6b23e0bf3b7cfb88aa5ba9 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -722,8 +722,8 @@ unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait) /* If there are subscribed events, then only use the new event API instead of the old video.h based API. */ - if (!list_empty(&id->fh.events->subscribed)) { - poll_wait(filp, &id->fh.events->wait, wait); + if (!list_empty(&id->fh.subscribed)) { + poll_wait(filp, &id->fh.wait, wait); /* Turn off the old-style vsync events */ clear_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); if (v4l2_event_pending(&id->fh)) @@ -750,6 +750,7 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags); + unsigned res = 0; /* Start a capture if there is none */ if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { @@ -769,12 +770,16 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) /* add stream's waitq to the poll list */ IVTV_DEBUG_HI_FILE("Encoder poll\n"); poll_wait(filp, &s->waitq, wait); + if (v4l2_event_pending(&id->fh)) + res |= POLLPRI; + else + poll_wait(filp, &id->fh.wait, wait); if (s->q_full.length || s->q_io.length) - return POLLIN | POLLRDNORM; + return res | POLLIN | POLLRDNORM; if (eof) - return POLLHUP; - return 0; + return res | POLLHUP; + return res; } void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) @@ -961,10 +966,6 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) return -ENOMEM; } v4l2_fh_init(&item->fh, s->vdev); - if (s->type == IVTV_DEC_STREAM_TYPE_YUV || - s->type == IVTV_DEC_STREAM_TYPE_MPG) { - res = v4l2_event_alloc(&item->fh, 60); - } if (res < 0) { v4l2_fh_exit(&item->fh); kfree(item); diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 120c7d8e0895ea36619e97759b34b0184edd2bf6..3e5c090af112bf12fb229bda27166e08db935d3d 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -757,7 +757,6 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); strlcpy(vcap->card, itv->card_name, sizeof(vcap->card)); snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev)); - vcap->version = IVTV_DRIVER_VERSION; /* version */ vcap->capabilities = itv->v4l2_cap; /* capabilities */ return 0; } @@ -1451,11 +1450,11 @@ static int ivtv_subscribe_event(struct v4l2_fh *fh, struct v4l2_event_subscripti switch (sub->type) { case V4L2_EVENT_VSYNC: case V4L2_EVENT_EOS: - break; + case V4L2_EVENT_CTRL: + return v4l2_event_subscribe(fh, sub, 0); default: return -EINVAL; } - return v4l2_event_subscribe(fh, sub); } static int ivtv_log_status(struct file *file, void *fh) diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h index b67a4048f5aa422fe7c198ae467c58fdd6c3b964..a20f346fcad89b4ef245423b579e072da14965ec 100644 --- a/drivers/media/video/ivtv/ivtv-version.h +++ b/drivers/media/video/ivtv/ivtv-version.h @@ -21,11 +21,6 @@ #define IVTV_VERSION_H #define IVTV_DRIVER_NAME "ivtv" -#define IVTV_DRIVER_VERSION_MAJOR 1 -#define IVTV_DRIVER_VERSION_MINOR 4 -#define IVTV_DRIVER_VERSION_PATCHLEVEL 2 - -#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) -#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL) +#define IVTV_VERSION "1.4.3" #endif diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c index a45d8f098e02a200a52c05a4155866050bb15c6b..3248ac8057119dcabbe0c726206f9fa60e2ca612 100644 --- a/drivers/media/video/m5mols/m5mols_capture.c +++ b/drivers/media/video/m5mols/m5mols_capture.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c index 43c68f51c5ce07822b58b44de9efe7749e1c3cf9..fb8e4a7a9dd29f27fdf96a5191a4e1581f5ddf56 100644 --- a/drivers/media/video/m5mols/m5mols_core.c +++ b/drivers/media/video/m5mols/m5mols_core.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/marvell-ccic/Kconfig b/drivers/media/video/marvell-ccic/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..bf739e3b33984c0ef36d262fa5b70426c74f41ce --- /dev/null +++ b/drivers/media/video/marvell-ccic/Kconfig @@ -0,0 +1,23 @@ +config VIDEO_CAFE_CCIC + tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support" + depends on PCI && I2C && VIDEO_V4L2 + select VIDEO_OV7670 + select VIDEOBUF2_VMALLOC + select VIDEOBUF2_DMA_CONTIG + ---help--- + This is a video4linux2 driver for the Marvell 88ALP01 integrated + CMOS camera controller. This is the controller found on first- + generation OLPC systems. + +config VIDEO_MMP_CAMERA + tristate "Marvell Armada 610 integrated camera controller support" + depends on ARCH_MMP && I2C && VIDEO_V4L2 + select VIDEO_OV7670 + select I2C_GPIO + select VIDEOBUF2_DMA_SG + ---help--- + This is a Video4Linux2 driver for the integrated camera + controller found on Marvell Armada 610 application + processors (and likely beyond). This is the controller found + in OLPC XO 1.75 systems. + diff --git a/drivers/media/video/marvell-ccic/Makefile b/drivers/media/video/marvell-ccic/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..05a792c579a22a14e57ed1038630f9949a56b2b1 --- /dev/null +++ b/drivers/media/video/marvell-ccic/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o +cafe_ccic-y := cafe-driver.o mcam-core.o + +obj-$(CONFIG_VIDEO_MMP_CAMERA) += mmp_camera.o +mmp_camera-y := mmp-driver.o mcam-core.o + diff --git a/drivers/media/video/marvell-ccic/cafe-driver.c b/drivers/media/video/marvell-ccic/cafe-driver.c new file mode 100644 index 0000000000000000000000000000000000000000..d030f9beae88b6bb37130b0ab199758e871bb410 --- /dev/null +++ b/drivers/media/video/marvell-ccic/cafe-driver.c @@ -0,0 +1,654 @@ +/* + * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe" + * multifunction chip. Currently works with the Omnivision OV7670 + * sensor. + * + * The data sheet for this device can be found at: + * http://www.marvell.com/products/pc_connectivity/88alp01/ + * + * Copyright 2006-11 One Laptop Per Child Association, Inc. + * Copyright 2006-11 Jonathan Corbet + * + * Written by Jonathan Corbet, corbet@lwn.net. + * + * v4l2_device/v4l2_subdev conversion by: + * Copyright (C) 2009 Hans Verkuil + * + * This file may be distributed under the terms of the GNU General + * Public License, version 2. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mcam-core.h" + +#define CAFE_VERSION 0x000002 + + +/* + * Parameters. + */ +MODULE_AUTHOR("Jonathan Corbet "); +MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("Video"); + + + + +struct cafe_camera { + int registered; /* Fully initialized? */ + struct mcam_camera mcam; + struct pci_dev *pdev; + wait_queue_head_t smbus_wait; /* Waiting on i2c events */ +}; + +/* + * Most of the camera controller registers are defined in mcam-core.h, + * but the Cafe platform has some additional registers of its own; + * they are described here. + */ + +/* + * "General purpose register" has a couple of GPIOs used for sensor + * power and reset on OLPC XO 1.0 systems. + */ +#define REG_GPR 0xb4 +#define GPR_C1EN 0x00000020 /* Pad 1 (power down) enable */ +#define GPR_C0EN 0x00000010 /* Pad 0 (reset) enable */ +#define GPR_C1 0x00000002 /* Control 1 value */ +/* + * Control 0 is wired to reset on OLPC machines. For ov7x sensors, + * it is active low. + */ +#define GPR_C0 0x00000001 /* Control 0 value */ + +/* + * These registers control the SMBUS module for communicating + * with the sensor. + */ +#define REG_TWSIC0 0xb8 /* TWSI (smbus) control 0 */ +#define TWSIC0_EN 0x00000001 /* TWSI enable */ +#define TWSIC0_MODE 0x00000002 /* 1 = 16-bit, 0 = 8-bit */ +#define TWSIC0_SID 0x000003fc /* Slave ID */ +/* + * Subtle trickery: the slave ID field starts with bit 2. But the + * Linux i2c stack wants to treat the bottommost bit as a separate + * read/write bit, which is why slave ID's are usually presented + * >>1. For consistency with that behavior, we shift over three + * bits instead of two. + */ +#define TWSIC0_SID_SHIFT 3 +#define TWSIC0_CLKDIV 0x0007fc00 /* Clock divider */ +#define TWSIC0_MASKACK 0x00400000 /* Mask ack from sensor */ +#define TWSIC0_OVMAGIC 0x00800000 /* Make it work on OV sensors */ + +#define REG_TWSIC1 0xbc /* TWSI control 1 */ +#define TWSIC1_DATA 0x0000ffff /* Data to/from camchip */ +#define TWSIC1_ADDR 0x00ff0000 /* Address (register) */ +#define TWSIC1_ADDR_SHIFT 16 +#define TWSIC1_READ 0x01000000 /* Set for read op */ +#define TWSIC1_WSTAT 0x02000000 /* Write status */ +#define TWSIC1_RVALID 0x04000000 /* Read data valid */ +#define TWSIC1_ERROR 0x08000000 /* Something screwed up */ + +/* + * Here's the weird global control registers + */ +#define REG_GL_CSR 0x3004 /* Control/status register */ +#define GCSR_SRS 0x00000001 /* SW Reset set */ +#define GCSR_SRC 0x00000002 /* SW Reset clear */ +#define GCSR_MRS 0x00000004 /* Master reset set */ +#define GCSR_MRC 0x00000008 /* HW Reset clear */ +#define GCSR_CCIC_EN 0x00004000 /* CCIC Clock enable */ +#define REG_GL_IMASK 0x300c /* Interrupt mask register */ +#define GIMSK_CCIC_EN 0x00000004 /* CCIC Interrupt enable */ + +#define REG_GL_FCR 0x3038 /* GPIO functional control register */ +#define GFCR_GPIO_ON 0x08 /* Camera GPIO enabled */ +#define REG_GL_GPIOR 0x315c /* GPIO register */ +#define GGPIO_OUT 0x80000 /* GPIO output */ +#define GGPIO_VAL 0x00008 /* Output pin value */ + +#define REG_LEN (REG_GL_IMASK + 4) + + +/* + * Debugging and related. + */ +#define cam_err(cam, fmt, arg...) \ + dev_err(&(cam)->pdev->dev, fmt, ##arg); +#define cam_warn(cam, fmt, arg...) \ + dev_warn(&(cam)->pdev->dev, fmt, ##arg); + +/* -------------------------------------------------------------------- */ +/* + * The I2C/SMBUS interface to the camera itself starts here. The + * controller handles SMBUS itself, presenting a relatively simple register + * interface; all we have to do is to tell it where to route the data. + */ +#define CAFE_SMBUS_TIMEOUT (HZ) /* generous */ + +static inline struct cafe_camera *to_cam(struct v4l2_device *dev) +{ + struct mcam_camera *m = container_of(dev, struct mcam_camera, v4l2_dev); + return container_of(m, struct cafe_camera, mcam); +} + + +static int cafe_smbus_write_done(struct mcam_camera *mcam) +{ + unsigned long flags; + int c1; + + /* + * We must delay after the interrupt, or the controller gets confused + * and never does give us good status. Fortunately, we don't do this + * often. + */ + udelay(20); + spin_lock_irqsave(&mcam->dev_lock, flags); + c1 = mcam_reg_read(mcam, REG_TWSIC1); + spin_unlock_irqrestore(&mcam->dev_lock, flags); + return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT; +} + +static int cafe_smbus_write_data(struct cafe_camera *cam, + u16 addr, u8 command, u8 value) +{ + unsigned int rval; + unsigned long flags; + struct mcam_camera *mcam = &cam->mcam; + + spin_lock_irqsave(&mcam->dev_lock, flags); + rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); + rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */ + /* + * Marvell sez set clkdiv to all 1's for now. + */ + rval |= TWSIC0_CLKDIV; + mcam_reg_write(mcam, REG_TWSIC0, rval); + (void) mcam_reg_read(mcam, REG_TWSIC1); /* force write */ + rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); + mcam_reg_write(mcam, REG_TWSIC1, rval); + spin_unlock_irqrestore(&mcam->dev_lock, flags); + + /* Unfortunately, reading TWSIC1 too soon after sending a command + * causes the device to die. + * Use a busy-wait because we often send a large quantity of small + * commands at-once; using msleep() would cause a lot of context + * switches which take longer than 2ms, resulting in a noticeable + * boot-time and capture-start delays. + */ + mdelay(2); + + /* + * Another sad fact is that sometimes, commands silently complete but + * cafe_smbus_write_done() never becomes aware of this. + * This happens at random and appears to possible occur with any + * command. + * We don't understand why this is. We work around this issue + * with the timeout in the wait below, assuming that all commands + * complete within the timeout. + */ + wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(mcam), + CAFE_SMBUS_TIMEOUT); + + spin_lock_irqsave(&mcam->dev_lock, flags); + rval = mcam_reg_read(mcam, REG_TWSIC1); + spin_unlock_irqrestore(&mcam->dev_lock, flags); + + if (rval & TWSIC1_WSTAT) { + cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr, + command, value); + return -EIO; + } + if (rval & TWSIC1_ERROR) { + cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr, + command, value); + return -EIO; + } + return 0; +} + + + +static int cafe_smbus_read_done(struct mcam_camera *mcam) +{ + unsigned long flags; + int c1; + + /* + * We must delay after the interrupt, or the controller gets confused + * and never does give us good status. Fortunately, we don't do this + * often. + */ + udelay(20); + spin_lock_irqsave(&mcam->dev_lock, flags); + c1 = mcam_reg_read(mcam, REG_TWSIC1); + spin_unlock_irqrestore(&mcam->dev_lock, flags); + return c1 & (TWSIC1_RVALID|TWSIC1_ERROR); +} + + + +static int cafe_smbus_read_data(struct cafe_camera *cam, + u16 addr, u8 command, u8 *value) +{ + unsigned int rval; + unsigned long flags; + struct mcam_camera *mcam = &cam->mcam; + + spin_lock_irqsave(&mcam->dev_lock, flags); + rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); + rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */ + /* + * Marvel sez set clkdiv to all 1's for now. + */ + rval |= TWSIC0_CLKDIV; + mcam_reg_write(mcam, REG_TWSIC0, rval); + (void) mcam_reg_read(mcam, REG_TWSIC1); /* force write */ + rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); + mcam_reg_write(mcam, REG_TWSIC1, rval); + spin_unlock_irqrestore(&mcam->dev_lock, flags); + + wait_event_timeout(cam->smbus_wait, + cafe_smbus_read_done(mcam), CAFE_SMBUS_TIMEOUT); + spin_lock_irqsave(&mcam->dev_lock, flags); + rval = mcam_reg_read(mcam, REG_TWSIC1); + spin_unlock_irqrestore(&mcam->dev_lock, flags); + + if (rval & TWSIC1_ERROR) { + cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command); + return -EIO; + } + if (!(rval & TWSIC1_RVALID)) { + cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr, + command); + return -EIO; + } + *value = rval & 0xff; + return 0; +} + +/* + * Perform a transfer over SMBUS. This thing is called under + * the i2c bus lock, so we shouldn't race with ourselves... + */ +static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr, + unsigned short flags, char rw, u8 command, + int size, union i2c_smbus_data *data) +{ + struct cafe_camera *cam = i2c_get_adapdata(adapter); + int ret = -EINVAL; + + /* + * This interface would appear to only do byte data ops. OK + * it can do word too, but the cam chip has no use for that. + */ + if (size != I2C_SMBUS_BYTE_DATA) { + cam_err(cam, "funky xfer size %d\n", size); + return -EINVAL; + } + + if (rw == I2C_SMBUS_WRITE) + ret = cafe_smbus_write_data(cam, addr, command, data->byte); + else if (rw == I2C_SMBUS_READ) + ret = cafe_smbus_read_data(cam, addr, command, &data->byte); + return ret; +} + + +static void cafe_smbus_enable_irq(struct cafe_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->mcam.dev_lock, flags); + mcam_reg_set_bit(&cam->mcam, REG_IRQMASK, TWSIIRQS); + spin_unlock_irqrestore(&cam->mcam.dev_lock, flags); +} + +static u32 cafe_smbus_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_READ_BYTE_DATA | + I2C_FUNC_SMBUS_WRITE_BYTE_DATA; +} + +static struct i2c_algorithm cafe_smbus_algo = { + .smbus_xfer = cafe_smbus_xfer, + .functionality = cafe_smbus_func +}; + +static int cafe_smbus_setup(struct cafe_camera *cam) +{ + struct i2c_adapter *adap; + int ret; + + adap = kzalloc(sizeof(*adap), GFP_KERNEL); + if (adap == NULL) + return -ENOMEM; + cam->mcam.i2c_adapter = adap; + cafe_smbus_enable_irq(cam); + adap->owner = THIS_MODULE; + adap->algo = &cafe_smbus_algo; + strcpy(adap->name, "cafe_ccic"); + adap->dev.parent = &cam->pdev->dev; + i2c_set_adapdata(adap, cam); + ret = i2c_add_adapter(adap); + if (ret) + printk(KERN_ERR "Unable to register cafe i2c adapter\n"); + return ret; +} + +static void cafe_smbus_shutdown(struct cafe_camera *cam) +{ + i2c_del_adapter(cam->mcam.i2c_adapter); + kfree(cam->mcam.i2c_adapter); +} + + +/* + * Controller-level stuff + */ + +static void cafe_ctlr_init(struct mcam_camera *mcam) +{ + unsigned long flags; + + spin_lock_irqsave(&mcam->dev_lock, flags); + /* + * Added magic to bring up the hardware on the B-Test board + */ + mcam_reg_write(mcam, 0x3038, 0x8); + mcam_reg_write(mcam, 0x315c, 0x80008); + /* + * Go through the dance needed to wake the device up. + * Note that these registers are global and shared + * with the NAND and SD devices. Interaction between the + * three still needs to be examined. + */ + mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */ + mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRC|GCSR_MRC); + mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRC|GCSR_MRS); + /* + * Here we must wait a bit for the controller to come around. + */ + spin_unlock_irqrestore(&mcam->dev_lock, flags); + msleep(5); + spin_lock_irqsave(&mcam->dev_lock, flags); + + mcam_reg_write(mcam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC); + mcam_reg_set_bit(mcam, REG_GL_IMASK, GIMSK_CCIC_EN); + /* + * Mask all interrupts. + */ + mcam_reg_write(mcam, REG_IRQMASK, 0); + spin_unlock_irqrestore(&mcam->dev_lock, flags); +} + + +static void cafe_ctlr_power_up(struct mcam_camera *mcam) +{ + /* + * Part one of the sensor dance: turn the global + * GPIO signal on. + */ + mcam_reg_write(mcam, REG_GL_FCR, GFCR_GPIO_ON); + mcam_reg_write(mcam, REG_GL_GPIOR, GGPIO_OUT|GGPIO_VAL); + /* + * Put the sensor into operational mode (assumes OLPC-style + * wiring). Control 0 is reset - set to 1 to operate. + * Control 1 is power down, set to 0 to operate. + */ + mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */ + mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); +} + +static void cafe_ctlr_power_down(struct mcam_camera *mcam) +{ + mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1); + mcam_reg_write(mcam, REG_GL_FCR, GFCR_GPIO_ON); + mcam_reg_write(mcam, REG_GL_GPIOR, GGPIO_OUT); +} + + + +/* + * The platform interrupt handler. + */ +static irqreturn_t cafe_irq(int irq, void *data) +{ + struct cafe_camera *cam = data; + struct mcam_camera *mcam = &cam->mcam; + unsigned int irqs, handled; + + spin_lock(&mcam->dev_lock); + irqs = mcam_reg_read(mcam, REG_IRQSTAT); + handled = cam->registered && mccic_irq(mcam, irqs); + if (irqs & TWSIIRQS) { + mcam_reg_write(mcam, REG_IRQSTAT, TWSIIRQS); + wake_up(&cam->smbus_wait); + handled = 1; + } + spin_unlock(&mcam->dev_lock); + return IRQ_RETVAL(handled); +} + + +/* -------------------------------------------------------------------------- */ +/* + * PCI interface stuff. + */ + +static int cafe_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int ret; + struct cafe_camera *cam; + struct mcam_camera *mcam; + + /* + * Start putting together one of our big camera structures. + */ + ret = -ENOMEM; + cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL); + if (cam == NULL) + goto out; + cam->pdev = pdev; + mcam = &cam->mcam; + mcam->chip_id = V4L2_IDENT_CAFE; + spin_lock_init(&mcam->dev_lock); + init_waitqueue_head(&cam->smbus_wait); + mcam->plat_power_up = cafe_ctlr_power_up; + mcam->plat_power_down = cafe_ctlr_power_down; + mcam->dev = &pdev->dev; + /* + * Set the clock speed for the XO 1; I don't believe this + * driver has ever run anywhere else. + */ + mcam->clock_speed = 45; + mcam->use_smbus = 1; + /* + * Vmalloc mode for buffers is traditional with this driver. + * We *might* be able to run DMA_contig, especially on a system + * with CMA in it. + */ + mcam->buffer_mode = B_vmalloc; + /* + * Get set up on the PCI bus. + */ + ret = pci_enable_device(pdev); + if (ret) + goto out_free; + pci_set_master(pdev); + + ret = -EIO; + mcam->regs = pci_iomap(pdev, 0, 0); + if (!mcam->regs) { + printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n"); + goto out_disable; + } + ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam); + if (ret) + goto out_iounmap; + + /* + * Initialize the controller and leave it powered up. It will + * stay that way until the sensor driver shows up. + */ + cafe_ctlr_init(mcam); + cafe_ctlr_power_up(mcam); + /* + * Set up I2C/SMBUS communications. We have to drop the mutex here + * because the sensor could attach in this call chain, leading to + * unsightly deadlocks. + */ + ret = cafe_smbus_setup(cam); + if (ret) + goto out_pdown; + + ret = mccic_register(mcam); + if (ret == 0) { + cam->registered = 1; + return 0; + } + + cafe_smbus_shutdown(cam); +out_pdown: + cafe_ctlr_power_down(mcam); + free_irq(pdev->irq, cam); +out_iounmap: + pci_iounmap(pdev, mcam->regs); +out_disable: + pci_disable_device(pdev); +out_free: + kfree(cam); +out: + return ret; +} + + +/* + * Shut down an initialized device + */ +static void cafe_shutdown(struct cafe_camera *cam) +{ + mccic_shutdown(&cam->mcam); + cafe_smbus_shutdown(cam); + free_irq(cam->pdev->irq, cam); + pci_iounmap(cam->pdev, cam->mcam.regs); +} + + +static void cafe_pci_remove(struct pci_dev *pdev) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct cafe_camera *cam = to_cam(v4l2_dev); + + if (cam == NULL) { + printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev); + return; + } + cafe_shutdown(cam); + kfree(cam); +} + + +#ifdef CONFIG_PM +/* + * Basic power management. + */ +static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct cafe_camera *cam = to_cam(v4l2_dev); + int ret; + + ret = pci_save_state(pdev); + if (ret) + return ret; + mccic_suspend(&cam->mcam); + pci_disable_device(pdev); + return 0; +} + + +static int cafe_pci_resume(struct pci_dev *pdev) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct cafe_camera *cam = to_cam(v4l2_dev); + int ret = 0; + + pci_restore_state(pdev); + ret = pci_enable_device(pdev); + + if (ret) { + cam_warn(cam, "Unable to re-enable device on resume!\n"); + return ret; + } + cafe_ctlr_init(&cam->mcam); + return mccic_resume(&cam->mcam); +} + +#endif /* CONFIG_PM */ + +static struct pci_device_id cafe_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, + PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, cafe_ids); + +static struct pci_driver cafe_pci_driver = { + .name = "cafe1000-ccic", + .id_table = cafe_ids, + .probe = cafe_pci_probe, + .remove = cafe_pci_remove, +#ifdef CONFIG_PM + .suspend = cafe_pci_suspend, + .resume = cafe_pci_resume, +#endif +}; + + + + +static int __init cafe_init(void) +{ + int ret; + + printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n", + CAFE_VERSION); + ret = pci_register_driver(&cafe_pci_driver); + if (ret) { + printk(KERN_ERR "Unable to register cafe_ccic driver\n"); + goto out; + } + ret = 0; + +out: + return ret; +} + + +static void __exit cafe_exit(void) +{ + pci_unregister_driver(&cafe_pci_driver); +} + +module_init(cafe_init); +module_exit(cafe_exit); diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c new file mode 100644 index 0000000000000000000000000000000000000000..83c14514cd52c5db2fce764c420506ed02c687a2 --- /dev/null +++ b/drivers/media/video/marvell-ccic/mcam-core.c @@ -0,0 +1,1843 @@ +/* + * The Marvell camera core. This device appears in a number of settings, + * so it needs platform-specific support outside of the core. + * + * Copyright 2011 Jonathan Corbet corbet@lwn.net + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mcam-core.h" + +/* + * Basic frame stats - to be deleted shortly + */ +static int frames; +static int singles; +static int delivered; + +#ifdef MCAM_MODE_VMALLOC +/* + * Internal DMA buffer management. Since the controller cannot do S/G I/O, + * we must have physically contiguous buffers to bring frames into. + * These parameters control how many buffers we use, whether we + * allocate them at load time (better chance of success, but nails down + * memory) or when somebody tries to use the camera (riskier), and, + * for load-time allocation, how big they should be. + * + * The controller can cycle through three buffers. We could use + * more by flipping pointers around, but it probably makes little + * sense. + */ + +static int alloc_bufs_at_read; +module_param(alloc_bufs_at_read, bool, 0444); +MODULE_PARM_DESC(alloc_bufs_at_read, + "Non-zero value causes DMA buffers to be allocated when the " + "video capture device is read, rather than at module load " + "time. This saves memory, but decreases the chances of " + "successfully getting those buffers. This parameter is " + "only used in the vmalloc buffer mode"); + +static int n_dma_bufs = 3; +module_param(n_dma_bufs, uint, 0644); +MODULE_PARM_DESC(n_dma_bufs, + "The number of DMA buffers to allocate. Can be either two " + "(saves memory, makes timing tighter) or three."); + +static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2; /* Worst case */ +module_param(dma_buf_size, uint, 0444); +MODULE_PARM_DESC(dma_buf_size, + "The size of the allocated DMA buffers. If actual operating " + "parameters require larger buffers, an attempt to reallocate " + "will be made."); +#else /* MCAM_MODE_VMALLOC */ +static const int alloc_bufs_at_read = 0; +static const int n_dma_bufs = 3; /* Used by S/G_PARM */ +#endif /* MCAM_MODE_VMALLOC */ + +static int flip; +module_param(flip, bool, 0444); +MODULE_PARM_DESC(flip, + "If set, the sensor will be instructed to flip the image " + "vertically."); + +static int buffer_mode = -1; +module_param(buffer_mode, int, 0444); +MODULE_PARM_DESC(buffer_mode, + "Set the buffer mode to be used; default is to go with what " + "the platform driver asks for. Set to 0 for vmalloc, 1 for " + "DMA contiguous."); + +/* + * Status flags. Always manipulated with bit operations. + */ +#define CF_BUF0_VALID 0 /* Buffers valid - first three */ +#define CF_BUF1_VALID 1 +#define CF_BUF2_VALID 2 +#define CF_DMA_ACTIVE 3 /* A frame is incoming */ +#define CF_CONFIG_NEEDED 4 /* Must configure hardware */ +#define CF_SINGLE_BUFFER 5 /* Running with a single buffer */ +#define CF_SG_RESTART 6 /* SG restart needed */ + +#define sensor_call(cam, o, f, args...) \ + v4l2_subdev_call(cam->sensor, o, f, ##args) + +static struct mcam_format_struct { + __u8 *desc; + __u32 pixelformat; + int bpp; /* Bytes per pixel */ + enum v4l2_mbus_pixelcode mbus_code; +} mcam_formats[] = { + { + .desc = "YUYV 4:2:2", + .pixelformat = V4L2_PIX_FMT_YUYV, + .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + .bpp = 2, + }, + { + .desc = "RGB 444", + .pixelformat = V4L2_PIX_FMT_RGB444, + .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE, + .bpp = 2, + }, + { + .desc = "RGB 565", + .pixelformat = V4L2_PIX_FMT_RGB565, + .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, + .bpp = 2, + }, + { + .desc = "Raw RGB Bayer", + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .mbus_code = V4L2_MBUS_FMT_SBGGR8_1X8, + .bpp = 1 + }, +}; +#define N_MCAM_FMTS ARRAY_SIZE(mcam_formats) + +static struct mcam_format_struct *mcam_find_format(u32 pixelformat) +{ + unsigned i; + + for (i = 0; i < N_MCAM_FMTS; i++) + if (mcam_formats[i].pixelformat == pixelformat) + return mcam_formats + i; + /* Not found? Then return the first format. */ + return mcam_formats; +} + +/* + * The default format we use until somebody says otherwise. + */ +static const struct v4l2_pix_format mcam_def_pix_format = { + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + .pixelformat = V4L2_PIX_FMT_YUYV, + .field = V4L2_FIELD_NONE, + .bytesperline = VGA_WIDTH*2, + .sizeimage = VGA_WIDTH*VGA_HEIGHT*2, +}; + +static const enum v4l2_mbus_pixelcode mcam_def_mbus_code = + V4L2_MBUS_FMT_YUYV8_2X8; + + +/* + * The two-word DMA descriptor format used by the Armada 610 and like. There + * Is a three-word format as well (set C1_DESC_3WORD) where the third + * word is a pointer to the next descriptor, but we don't use it. Two-word + * descriptors have to be contiguous in memory. + */ +struct mcam_dma_desc { + u32 dma_addr; + u32 segment_len; +}; + +/* + * Our buffer type for working with videobuf2. Note that the vb2 + * developers have decreed that struct vb2_buffer must be at the + * beginning of this structure. + */ +struct mcam_vb_buffer { + struct vb2_buffer vb_buf; + struct list_head queue; + struct mcam_dma_desc *dma_desc; /* Descriptor virtual address */ + dma_addr_t dma_desc_pa; /* Descriptor physical address */ + int dma_desc_nent; /* Number of mapped descriptors */ +}; + +static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_buffer *vb) +{ + return container_of(vb, struct mcam_vb_buffer, vb_buf); +} + +/* + * Hand a completed buffer back to user space. + */ +static void mcam_buffer_done(struct mcam_camera *cam, int frame, + struct vb2_buffer *vbuf) +{ + vbuf->v4l2_buf.bytesused = cam->pix_format.sizeimage; + vbuf->v4l2_buf.sequence = cam->buf_seq[frame]; + vb2_set_plane_payload(vbuf, 0, cam->pix_format.sizeimage); + vb2_buffer_done(vbuf, VB2_BUF_STATE_DONE); +} + + + +/* + * Debugging and related. + */ +#define cam_err(cam, fmt, arg...) \ + dev_err((cam)->dev, fmt, ##arg); +#define cam_warn(cam, fmt, arg...) \ + dev_warn((cam)->dev, fmt, ##arg); +#define cam_dbg(cam, fmt, arg...) \ + dev_dbg((cam)->dev, fmt, ##arg); + + +/* + * Flag manipulation helpers + */ +static void mcam_reset_buffers(struct mcam_camera *cam) +{ + int i; + + cam->next_buf = -1; + for (i = 0; i < cam->nbufs; i++) + clear_bit(i, &cam->flags); +} + +static inline int mcam_needs_config(struct mcam_camera *cam) +{ + return test_bit(CF_CONFIG_NEEDED, &cam->flags); +} + +static void mcam_set_config_needed(struct mcam_camera *cam, int needed) +{ + if (needed) + set_bit(CF_CONFIG_NEEDED, &cam->flags); + else + clear_bit(CF_CONFIG_NEEDED, &cam->flags); +} + +/* ------------------------------------------------------------------- */ +/* + * Make the controller start grabbing images. Everything must + * be set up before doing this. + */ +static void mcam_ctlr_start(struct mcam_camera *cam) +{ + /* set_bit performs a read, so no other barrier should be + needed here */ + mcam_reg_set_bit(cam, REG_CTRL0, C0_ENABLE); +} + +static void mcam_ctlr_stop(struct mcam_camera *cam) +{ + mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); +} + +/* ------------------------------------------------------------------- */ + +#ifdef MCAM_MODE_VMALLOC +/* + * Code specific to the vmalloc buffer mode. + */ + +/* + * Allocate in-kernel DMA buffers for vmalloc mode. + */ +static int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime) +{ + int i; + + mcam_set_config_needed(cam, 1); + if (loadtime) + cam->dma_buf_size = dma_buf_size; + else + cam->dma_buf_size = cam->pix_format.sizeimage; + if (n_dma_bufs > 3) + n_dma_bufs = 3; + + cam->nbufs = 0; + for (i = 0; i < n_dma_bufs; i++) { + cam->dma_bufs[i] = dma_alloc_coherent(cam->dev, + cam->dma_buf_size, cam->dma_handles + i, + GFP_KERNEL); + if (cam->dma_bufs[i] == NULL) { + cam_warn(cam, "Failed to allocate DMA buffer\n"); + break; + } + (cam->nbufs)++; + } + + switch (cam->nbufs) { + case 1: + dma_free_coherent(cam->dev, cam->dma_buf_size, + cam->dma_bufs[0], cam->dma_handles[0]); + cam->nbufs = 0; + case 0: + cam_err(cam, "Insufficient DMA buffers, cannot operate\n"); + return -ENOMEM; + + case 2: + if (n_dma_bufs > 2) + cam_warn(cam, "Will limp along with only 2 buffers\n"); + break; + } + return 0; +} + +static void mcam_free_dma_bufs(struct mcam_camera *cam) +{ + int i; + + for (i = 0; i < cam->nbufs; i++) { + dma_free_coherent(cam->dev, cam->dma_buf_size, + cam->dma_bufs[i], cam->dma_handles[i]); + cam->dma_bufs[i] = NULL; + } + cam->nbufs = 0; +} + + +/* + * Set up DMA buffers when operating in vmalloc mode + */ +static void mcam_ctlr_dma_vmalloc(struct mcam_camera *cam) +{ + /* + * Store the first two Y buffers (we aren't supporting + * planar formats for now, so no UV bufs). Then either + * set the third if it exists, or tell the controller + * to just use two. + */ + mcam_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]); + mcam_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]); + if (cam->nbufs > 2) { + mcam_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]); + mcam_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS); + } else + mcam_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS); + if (cam->chip_id == V4L2_IDENT_CAFE) + mcam_reg_write(cam, REG_UBAR, 0); /* 32 bits only */ +} + +/* + * Copy data out to user space in the vmalloc case + */ +static void mcam_frame_tasklet(unsigned long data) +{ + struct mcam_camera *cam = (struct mcam_camera *) data; + int i; + unsigned long flags; + struct mcam_vb_buffer *buf; + + spin_lock_irqsave(&cam->dev_lock, flags); + for (i = 0; i < cam->nbufs; i++) { + int bufno = cam->next_buf; + + if (cam->state != S_STREAMING || bufno < 0) + break; /* I/O got stopped */ + if (++(cam->next_buf) >= cam->nbufs) + cam->next_buf = 0; + if (!test_bit(bufno, &cam->flags)) + continue; + if (list_empty(&cam->buffers)) { + singles++; + break; /* Leave it valid, hope for better later */ + } + delivered++; + clear_bit(bufno, &cam->flags); + buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, + queue); + list_del_init(&buf->queue); + /* + * Drop the lock during the big copy. This *should* be safe... + */ + spin_unlock_irqrestore(&cam->dev_lock, flags); + memcpy(vb2_plane_vaddr(&buf->vb_buf, 0), cam->dma_bufs[bufno], + cam->pix_format.sizeimage); + mcam_buffer_done(cam, bufno, &buf->vb_buf); + spin_lock_irqsave(&cam->dev_lock, flags); + } + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + + +/* + * Make sure our allocated buffers are up to the task. + */ +static int mcam_check_dma_buffers(struct mcam_camera *cam) +{ + if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage) + mcam_free_dma_bufs(cam); + if (cam->nbufs == 0) + return mcam_alloc_dma_bufs(cam, 0); + return 0; +} + +static void mcam_vmalloc_done(struct mcam_camera *cam, int frame) +{ + tasklet_schedule(&cam->s_tasklet); +} + +#else /* MCAM_MODE_VMALLOC */ + +static inline int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime) +{ + return 0; +} + +static inline void mcam_free_dma_bufs(struct mcam_camera *cam) +{ + return; +} + +static inline int mcam_check_dma_buffers(struct mcam_camera *cam) +{ + return 0; +} + + + +#endif /* MCAM_MODE_VMALLOC */ + + +#ifdef MCAM_MODE_DMA_CONTIG +/* ---------------------------------------------------------------------- */ +/* + * DMA-contiguous code. + */ +/* + * Set up a contiguous buffer for the given frame. Here also is where + * the underrun strategy is set: if there is no buffer available, reuse + * the buffer from the other BAR and set the CF_SINGLE_BUFFER flag to + * keep the interrupt handler from giving that buffer back to user + * space. In this way, we always have a buffer to DMA to and don't + * have to try to play games stopping and restarting the controller. + */ +static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame) +{ + struct mcam_vb_buffer *buf; + /* + * If there are no available buffers, go into single mode + */ + if (list_empty(&cam->buffers)) { + buf = cam->vb_bufs[frame ^ 0x1]; + cam->vb_bufs[frame] = buf; + mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR, + vb2_dma_contig_plane_paddr(&buf->vb_buf, 0)); + set_bit(CF_SINGLE_BUFFER, &cam->flags); + singles++; + return; + } + /* + * OK, we have a buffer we can use. + */ + buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue); + list_del_init(&buf->queue); + mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR, + vb2_dma_contig_plane_paddr(&buf->vb_buf, 0)); + cam->vb_bufs[frame] = buf; + clear_bit(CF_SINGLE_BUFFER, &cam->flags); +} + +/* + * Initial B_DMA_contig setup. + */ +static void mcam_ctlr_dma_contig(struct mcam_camera *cam) +{ + mcam_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS); + cam->nbufs = 2; + mcam_set_contig_buffer(cam, 0); + mcam_set_contig_buffer(cam, 1); +} + +/* + * Frame completion handling. + */ +static void mcam_dma_contig_done(struct mcam_camera *cam, int frame) +{ + struct mcam_vb_buffer *buf = cam->vb_bufs[frame]; + + if (!test_bit(CF_SINGLE_BUFFER, &cam->flags)) { + delivered++; + mcam_buffer_done(cam, frame, &buf->vb_buf); + } + mcam_set_contig_buffer(cam, frame); +} + +#endif /* MCAM_MODE_DMA_CONTIG */ + +#ifdef MCAM_MODE_DMA_SG +/* ---------------------------------------------------------------------- */ +/* + * Scatter/gather-specific code. + */ + +/* + * Set up the next buffer for S/G I/O; caller should be sure that + * the controller is stopped and a buffer is available. + */ +static void mcam_sg_next_buffer(struct mcam_camera *cam) +{ + struct mcam_vb_buffer *buf; + + buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue); + list_del_init(&buf->queue); + mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa); + mcam_reg_write(cam, REG_DESC_LEN_Y, + buf->dma_desc_nent*sizeof(struct mcam_dma_desc)); + mcam_reg_write(cam, REG_DESC_LEN_U, 0); + mcam_reg_write(cam, REG_DESC_LEN_V, 0); + cam->vb_bufs[0] = buf; +} + +/* + * Initial B_DMA_sg setup + */ +static void mcam_ctlr_dma_sg(struct mcam_camera *cam) +{ + mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD); + mcam_sg_next_buffer(cam); + mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); + cam->nbufs = 3; +} + + +/* + * Frame completion with S/G is trickier. We can't muck with + * a descriptor chain on the fly, since the controller buffers it + * internally. So we have to actually stop and restart; Marvell + * says this is the way to do it. + * + * Of course, stopping is easier said than done; experience shows + * that the controller can start a frame *after* C0_ENABLE has been + * cleared. So when running in S/G mode, the controller is "stopped" + * on receipt of the start-of-frame interrupt. That means we can + * safely change the DMA descriptor array here and restart things + * (assuming there's another buffer waiting to go). + */ +static void mcam_dma_sg_done(struct mcam_camera *cam, int frame) +{ + struct mcam_vb_buffer *buf = cam->vb_bufs[0]; + + /* + * Very Bad Not Good Things happen if you don't clear + * C1_DESC_ENA before making any descriptor changes. + */ + mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA); + /* + * If we have another buffer available, put it in and + * restart the engine. + */ + if (!list_empty(&cam->buffers)) { + mcam_sg_next_buffer(cam); + mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); + mcam_ctlr_start(cam); + /* + * Otherwise set CF_SG_RESTART and the controller will + * be restarted once another buffer shows up. + */ + } else { + set_bit(CF_SG_RESTART, &cam->flags); + singles++; + } + /* + * Now we can give the completed frame back to user space. + */ + delivered++; + mcam_buffer_done(cam, frame, &buf->vb_buf); +} + + +/* + * Scatter/gather mode requires stopping the controller between + * frames so we can put in a new DMA descriptor array. If no new + * buffer exists at frame completion, the controller is left stopped; + * this function is charged with gettig things going again. + */ +static void mcam_sg_restart(struct mcam_camera *cam) +{ + mcam_ctlr_dma_sg(cam); + mcam_ctlr_start(cam); + clear_bit(CF_SG_RESTART, &cam->flags); +} + +#else /* MCAM_MODE_DMA_SG */ + +static inline void mcam_sg_restart(struct mcam_camera *cam) +{ + return; +} + +#endif /* MCAM_MODE_DMA_SG */ + +/* ---------------------------------------------------------------------- */ +/* + * Buffer-mode-independent controller code. + */ + +/* + * Image format setup + */ +static void mcam_ctlr_image(struct mcam_camera *cam) +{ + int imgsz; + struct v4l2_pix_format *fmt = &cam->pix_format; + + imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) | + (fmt->bytesperline & IMGSZ_H_MASK); + mcam_reg_write(cam, REG_IMGSIZE, imgsz); + mcam_reg_write(cam, REG_IMGOFFSET, 0); + /* YPITCH just drops the last two bits */ + mcam_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline, + IMGP_YP_MASK); + /* + * Tell the controller about the image format we are using. + */ + switch (cam->pix_format.pixelformat) { + case V4L2_PIX_FMT_YUYV: + mcam_reg_write_mask(cam, REG_CTRL0, + C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV, + C0_DF_MASK); + break; + + case V4L2_PIX_FMT_RGB444: + mcam_reg_write_mask(cam, REG_CTRL0, + C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB, + C0_DF_MASK); + /* Alpha value? */ + break; + + case V4L2_PIX_FMT_RGB565: + mcam_reg_write_mask(cam, REG_CTRL0, + C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR, + C0_DF_MASK); + break; + + default: + cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat); + break; + } + /* + * Make sure it knows we want to use hsync/vsync. + */ + mcam_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC, + C0_SIFM_MASK); +} + + +/* + * Configure the controller for operation; caller holds the + * device mutex. + */ +static int mcam_ctlr_configure(struct mcam_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + cam->dma_setup(cam); + mcam_ctlr_image(cam); + mcam_set_config_needed(cam, 0); + clear_bit(CF_SG_RESTART, &cam->flags); + spin_unlock_irqrestore(&cam->dev_lock, flags); + return 0; +} + +static void mcam_ctlr_irq_enable(struct mcam_camera *cam) +{ + /* + * Clear any pending interrupts, since we do not + * expect to have I/O active prior to enabling. + */ + mcam_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); + mcam_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS); +} + +static void mcam_ctlr_irq_disable(struct mcam_camera *cam) +{ + mcam_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS); +} + + + +static void mcam_ctlr_init(struct mcam_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + /* + * Make sure it's not powered down. + */ + mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); + /* + * Turn off the enable bit. It sure should be off anyway, + * but it's good to be sure. + */ + mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); + /* + * Clock the sensor appropriately. Controller clock should + * be 48MHz, sensor "typical" value is half that. + */ + mcam_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + + +/* + * Stop the controller, and don't return until we're really sure that no + * further DMA is going on. + */ +static void mcam_ctlr_stop_dma(struct mcam_camera *cam) +{ + unsigned long flags; + + /* + * Theory: stop the camera controller (whether it is operating + * or not). Delay briefly just in case we race with the SOF + * interrupt, then wait until no DMA is active. + */ + spin_lock_irqsave(&cam->dev_lock, flags); + clear_bit(CF_SG_RESTART, &cam->flags); + mcam_ctlr_stop(cam); + cam->state = S_IDLE; + spin_unlock_irqrestore(&cam->dev_lock, flags); + msleep(40); + if (test_bit(CF_DMA_ACTIVE, &cam->flags)) + cam_err(cam, "Timeout waiting for DMA to end\n"); + /* This would be bad news - what now? */ + spin_lock_irqsave(&cam->dev_lock, flags); + mcam_ctlr_irq_disable(cam); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + +/* + * Power up and down. + */ +static void mcam_ctlr_power_up(struct mcam_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + cam->plat_power_up(cam); + mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); + spin_unlock_irqrestore(&cam->dev_lock, flags); + msleep(5); /* Just to be sure */ +} + +static void mcam_ctlr_power_down(struct mcam_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + /* + * School of hard knocks department: be sure we do any register + * twiddling on the controller *before* calling the platform + * power down routine. + */ + mcam_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN); + cam->plat_power_down(cam); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + +/* -------------------------------------------------------------------- */ +/* + * Communications with the sensor. + */ + +static int __mcam_cam_reset(struct mcam_camera *cam) +{ + return sensor_call(cam, core, reset, 0); +} + +/* + * We have found the sensor on the i2c. Let's try to have a + * conversation. + */ +static int mcam_cam_init(struct mcam_camera *cam) +{ + struct v4l2_dbg_chip_ident chip; + int ret; + + mutex_lock(&cam->s_mutex); + if (cam->state != S_NOTREADY) + cam_warn(cam, "Cam init with device in funky state %d", + cam->state); + ret = __mcam_cam_reset(cam); + if (ret) + goto out; + chip.ident = V4L2_IDENT_NONE; + chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR; + chip.match.addr = cam->sensor_addr; + ret = sensor_call(cam, core, g_chip_ident, &chip); + if (ret) + goto out; + cam->sensor_type = chip.ident; + if (cam->sensor_type != V4L2_IDENT_OV7670) { + cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type); + ret = -EINVAL; + goto out; + } +/* Get/set parameters? */ + ret = 0; + cam->state = S_IDLE; +out: + mcam_ctlr_power_down(cam); + mutex_unlock(&cam->s_mutex); + return ret; +} + +/* + * Configure the sensor to match the parameters we have. Caller should + * hold s_mutex + */ +static int mcam_cam_set_flip(struct mcam_camera *cam) +{ + struct v4l2_control ctrl; + + memset(&ctrl, 0, sizeof(ctrl)); + ctrl.id = V4L2_CID_VFLIP; + ctrl.value = flip; + return sensor_call(cam, core, s_ctrl, &ctrl); +} + + +static int mcam_cam_configure(struct mcam_camera *cam) +{ + struct v4l2_mbus_framefmt mbus_fmt; + int ret; + + v4l2_fill_mbus_format(&mbus_fmt, &cam->pix_format, cam->mbus_code); + ret = sensor_call(cam, core, init, 0); + if (ret == 0) + ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt); + /* + * OV7670 does weird things if flip is set *before* format... + */ + ret += mcam_cam_set_flip(cam); + return ret; +} + +/* + * Get everything ready, and start grabbing frames. + */ +static int mcam_read_setup(struct mcam_camera *cam) +{ + int ret; + unsigned long flags; + + /* + * Configuration. If we still don't have DMA buffers, + * make one last, desperate attempt. + */ + if (cam->buffer_mode == B_vmalloc && cam->nbufs == 0 && + mcam_alloc_dma_bufs(cam, 0)) + return -ENOMEM; + + if (mcam_needs_config(cam)) { + mcam_cam_configure(cam); + ret = mcam_ctlr_configure(cam); + if (ret) + return ret; + } + + /* + * Turn it loose. + */ + spin_lock_irqsave(&cam->dev_lock, flags); + mcam_reset_buffers(cam); + mcam_ctlr_irq_enable(cam); + cam->state = S_STREAMING; + mcam_ctlr_start(cam); + spin_unlock_irqrestore(&cam->dev_lock, flags); + return 0; +} + +/* ----------------------------------------------------------------------- */ +/* + * Videobuf2 interface code. + */ + +static int mcam_vb_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, + unsigned int *num_planes, unsigned long sizes[], + void *alloc_ctxs[]) +{ + struct mcam_camera *cam = vb2_get_drv_priv(vq); + int minbufs = (cam->buffer_mode == B_DMA_contig) ? 3 : 2; + + sizes[0] = cam->pix_format.sizeimage; + *num_planes = 1; /* Someday we have to support planar formats... */ + if (*nbufs < minbufs) + *nbufs = minbufs; + if (cam->buffer_mode == B_DMA_contig) + alloc_ctxs[0] = cam->vb_alloc_ctx; + return 0; +} + + +static void mcam_vb_buf_queue(struct vb2_buffer *vb) +{ + struct mcam_vb_buffer *mvb = vb_to_mvb(vb); + struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue); + unsigned long flags; + int start; + + spin_lock_irqsave(&cam->dev_lock, flags); + start = (cam->state == S_BUFWAIT) && !list_empty(&cam->buffers); + list_add(&mvb->queue, &cam->buffers); + if (test_bit(CF_SG_RESTART, &cam->flags)) + mcam_sg_restart(cam); + spin_unlock_irqrestore(&cam->dev_lock, flags); + if (start) + mcam_read_setup(cam); +} + + +/* + * vb2 uses these to release the mutex when waiting in dqbuf. I'm + * not actually sure we need to do this (I'm not sure that vb2_dqbuf() needs + * to be called with the mutex held), but better safe than sorry. + */ +static void mcam_vb_wait_prepare(struct vb2_queue *vq) +{ + struct mcam_camera *cam = vb2_get_drv_priv(vq); + + mutex_unlock(&cam->s_mutex); +} + +static void mcam_vb_wait_finish(struct vb2_queue *vq) +{ + struct mcam_camera *cam = vb2_get_drv_priv(vq); + + mutex_lock(&cam->s_mutex); +} + +/* + * These need to be called with the mutex held from vb2 + */ +static int mcam_vb_start_streaming(struct vb2_queue *vq) +{ + struct mcam_camera *cam = vb2_get_drv_priv(vq); + + if (cam->state != S_IDLE) + return -EINVAL; + cam->sequence = 0; + /* + * Videobuf2 sneakily hoards all the buffers and won't + * give them to us until *after* streaming starts. But + * we can't actually start streaming until we have a + * destination. So go into a wait state and hope they + * give us buffers soon. + */ + if (cam->buffer_mode != B_vmalloc && list_empty(&cam->buffers)) { + cam->state = S_BUFWAIT; + return 0; + } + return mcam_read_setup(cam); +} + +static int mcam_vb_stop_streaming(struct vb2_queue *vq) +{ + struct mcam_camera *cam = vb2_get_drv_priv(vq); + unsigned long flags; + + if (cam->state == S_BUFWAIT) { + /* They never gave us buffers */ + cam->state = S_IDLE; + return 0; + } + if (cam->state != S_STREAMING) + return -EINVAL; + mcam_ctlr_stop_dma(cam); + /* + * VB2 reclaims the buffers, so we need to forget + * about them. + */ + spin_lock_irqsave(&cam->dev_lock, flags); + INIT_LIST_HEAD(&cam->buffers); + spin_unlock_irqrestore(&cam->dev_lock, flags); + return 0; +} + + +static const struct vb2_ops mcam_vb2_ops = { + .queue_setup = mcam_vb_queue_setup, + .buf_queue = mcam_vb_buf_queue, + .start_streaming = mcam_vb_start_streaming, + .stop_streaming = mcam_vb_stop_streaming, + .wait_prepare = mcam_vb_wait_prepare, + .wait_finish = mcam_vb_wait_finish, +}; + + +#ifdef MCAM_MODE_DMA_SG +/* + * Scatter/gather mode uses all of the above functions plus a + * few extras to deal with DMA mapping. + */ +static int mcam_vb_sg_buf_init(struct vb2_buffer *vb) +{ + struct mcam_vb_buffer *mvb = vb_to_mvb(vb); + struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue); + int ndesc = cam->pix_format.sizeimage/PAGE_SIZE + 1; + + mvb->dma_desc = dma_alloc_coherent(cam->dev, + ndesc * sizeof(struct mcam_dma_desc), + &mvb->dma_desc_pa, GFP_KERNEL); + if (mvb->dma_desc == NULL) { + cam_err(cam, "Unable to get DMA descriptor array\n"); + return -ENOMEM; + } + return 0; +} + +static int mcam_vb_sg_buf_prepare(struct vb2_buffer *vb) +{ + struct mcam_vb_buffer *mvb = vb_to_mvb(vb); + struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_dma_sg_desc *sgd = vb2_dma_sg_plane_desc(vb, 0); + struct mcam_dma_desc *desc = mvb->dma_desc; + struct scatterlist *sg; + int i; + + mvb->dma_desc_nent = dma_map_sg(cam->dev, sgd->sglist, sgd->num_pages, + DMA_FROM_DEVICE); + if (mvb->dma_desc_nent <= 0) + return -EIO; /* Not sure what's right here */ + for_each_sg(sgd->sglist, sg, mvb->dma_desc_nent, i) { + desc->dma_addr = sg_dma_address(sg); + desc->segment_len = sg_dma_len(sg); + desc++; + } + return 0; +} + +static int mcam_vb_sg_buf_finish(struct vb2_buffer *vb) +{ + struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_dma_sg_desc *sgd = vb2_dma_sg_plane_desc(vb, 0); + + dma_unmap_sg(cam->dev, sgd->sglist, sgd->num_pages, DMA_FROM_DEVICE); + return 0; +} + +static void mcam_vb_sg_buf_cleanup(struct vb2_buffer *vb) +{ + struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue); + struct mcam_vb_buffer *mvb = vb_to_mvb(vb); + int ndesc = cam->pix_format.sizeimage/PAGE_SIZE + 1; + + dma_free_coherent(cam->dev, ndesc * sizeof(struct mcam_dma_desc), + mvb->dma_desc, mvb->dma_desc_pa); +} + + +static const struct vb2_ops mcam_vb2_sg_ops = { + .queue_setup = mcam_vb_queue_setup, + .buf_init = mcam_vb_sg_buf_init, + .buf_prepare = mcam_vb_sg_buf_prepare, + .buf_queue = mcam_vb_buf_queue, + .buf_finish = mcam_vb_sg_buf_finish, + .buf_cleanup = mcam_vb_sg_buf_cleanup, + .start_streaming = mcam_vb_start_streaming, + .stop_streaming = mcam_vb_stop_streaming, + .wait_prepare = mcam_vb_wait_prepare, + .wait_finish = mcam_vb_wait_finish, +}; + +#endif /* MCAM_MODE_DMA_SG */ + +static int mcam_setup_vb2(struct mcam_camera *cam) +{ + struct vb2_queue *vq = &cam->vb_queue; + + memset(vq, 0, sizeof(*vq)); + vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vq->drv_priv = cam; + INIT_LIST_HEAD(&cam->buffers); + switch (cam->buffer_mode) { + case B_DMA_contig: +#ifdef MCAM_MODE_DMA_CONTIG + vq->ops = &mcam_vb2_ops; + vq->mem_ops = &vb2_dma_contig_memops; + cam->vb_alloc_ctx = vb2_dma_contig_init_ctx(cam->dev); + vq->io_modes = VB2_MMAP | VB2_USERPTR; + cam->dma_setup = mcam_ctlr_dma_contig; + cam->frame_complete = mcam_dma_contig_done; +#endif + break; + case B_DMA_sg: +#ifdef MCAM_MODE_DMA_SG + vq->ops = &mcam_vb2_sg_ops; + vq->mem_ops = &vb2_dma_sg_memops; + vq->io_modes = VB2_MMAP | VB2_USERPTR; + cam->dma_setup = mcam_ctlr_dma_sg; + cam->frame_complete = mcam_dma_sg_done; +#endif + break; + case B_vmalloc: +#ifdef MCAM_MODE_VMALLOC + tasklet_init(&cam->s_tasklet, mcam_frame_tasklet, + (unsigned long) cam); + vq->ops = &mcam_vb2_ops; + vq->mem_ops = &vb2_vmalloc_memops; + vq->buf_struct_size = sizeof(struct mcam_vb_buffer); + vq->io_modes = VB2_MMAP; + cam->dma_setup = mcam_ctlr_dma_vmalloc; + cam->frame_complete = mcam_vmalloc_done; +#endif + break; + } + return vb2_queue_init(vq); +} + +static void mcam_cleanup_vb2(struct mcam_camera *cam) +{ + vb2_queue_release(&cam->vb_queue); +#ifdef MCAM_MODE_DMA_CONTIG + if (cam->buffer_mode == B_DMA_contig) + vb2_dma_contig_cleanup_ctx(cam->vb_alloc_ctx); +#endif +} + + +/* ---------------------------------------------------------------------- */ +/* + * The long list of V4L2 ioctl() operations. + */ + +static int mcam_vidioc_streamon(struct file *filp, void *priv, + enum v4l2_buf_type type) +{ + struct mcam_camera *cam = filp->private_data; + int ret; + + mutex_lock(&cam->s_mutex); + ret = vb2_streamon(&cam->vb_queue, type); + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int mcam_vidioc_streamoff(struct file *filp, void *priv, + enum v4l2_buf_type type) +{ + struct mcam_camera *cam = filp->private_data; + int ret; + + mutex_lock(&cam->s_mutex); + ret = vb2_streamoff(&cam->vb_queue, type); + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int mcam_vidioc_reqbufs(struct file *filp, void *priv, + struct v4l2_requestbuffers *req) +{ + struct mcam_camera *cam = filp->private_data; + int ret; + + mutex_lock(&cam->s_mutex); + ret = vb2_reqbufs(&cam->vb_queue, req); + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int mcam_vidioc_querybuf(struct file *filp, void *priv, + struct v4l2_buffer *buf) +{ + struct mcam_camera *cam = filp->private_data; + int ret; + + mutex_lock(&cam->s_mutex); + ret = vb2_querybuf(&cam->vb_queue, buf); + mutex_unlock(&cam->s_mutex); + return ret; +} + +static int mcam_vidioc_qbuf(struct file *filp, void *priv, + struct v4l2_buffer *buf) +{ + struct mcam_camera *cam = filp->private_data; + int ret; + + mutex_lock(&cam->s_mutex); + ret = vb2_qbuf(&cam->vb_queue, buf); + mutex_unlock(&cam->s_mutex); + return ret; +} + +static int mcam_vidioc_dqbuf(struct file *filp, void *priv, + struct v4l2_buffer *buf) +{ + struct mcam_camera *cam = filp->private_data; + int ret; + + mutex_lock(&cam->s_mutex); + ret = vb2_dqbuf(&cam->vb_queue, buf, filp->f_flags & O_NONBLOCK); + mutex_unlock(&cam->s_mutex); + return ret; +} + + + +static int mcam_vidioc_queryctrl(struct file *filp, void *priv, + struct v4l2_queryctrl *qc) +{ + struct mcam_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = sensor_call(cam, core, queryctrl, qc); + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int mcam_vidioc_g_ctrl(struct file *filp, void *priv, + struct v4l2_control *ctrl) +{ + struct mcam_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = sensor_call(cam, core, g_ctrl, ctrl); + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int mcam_vidioc_s_ctrl(struct file *filp, void *priv, + struct v4l2_control *ctrl) +{ + struct mcam_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = sensor_call(cam, core, s_ctrl, ctrl); + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int mcam_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strcpy(cap->driver, "marvell_ccic"); + strcpy(cap->card, "marvell_ccic"); + cap->version = 1; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + return 0; +} + + +static int mcam_vidioc_enum_fmt_vid_cap(struct file *filp, + void *priv, struct v4l2_fmtdesc *fmt) +{ + if (fmt->index >= N_MCAM_FMTS) + return -EINVAL; + strlcpy(fmt->description, mcam_formats[fmt->index].desc, + sizeof(fmt->description)); + fmt->pixelformat = mcam_formats[fmt->index].pixelformat; + return 0; +} + +static int mcam_vidioc_try_fmt_vid_cap(struct file *filp, void *priv, + struct v4l2_format *fmt) +{ + struct mcam_camera *cam = priv; + struct mcam_format_struct *f; + struct v4l2_pix_format *pix = &fmt->fmt.pix; + struct v4l2_mbus_framefmt mbus_fmt; + int ret; + + f = mcam_find_format(pix->pixelformat); + pix->pixelformat = f->pixelformat; + v4l2_fill_mbus_format(&mbus_fmt, pix, f->mbus_code); + mutex_lock(&cam->s_mutex); + ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt); + mutex_unlock(&cam->s_mutex); + v4l2_fill_pix_format(pix, &mbus_fmt); + pix->bytesperline = pix->width * f->bpp; + pix->sizeimage = pix->height * pix->bytesperline; + return ret; +} + +static int mcam_vidioc_s_fmt_vid_cap(struct file *filp, void *priv, + struct v4l2_format *fmt) +{ + struct mcam_camera *cam = priv; + struct mcam_format_struct *f; + int ret; + + /* + * Can't do anything if the device is not idle + * Also can't if there are streaming buffers in place. + */ + if (cam->state != S_IDLE || cam->vb_queue.num_buffers > 0) + return -EBUSY; + + f = mcam_find_format(fmt->fmt.pix.pixelformat); + + /* + * See if the formatting works in principle. + */ + ret = mcam_vidioc_try_fmt_vid_cap(filp, priv, fmt); + if (ret) + return ret; + /* + * Now we start to change things for real, so let's do it + * under lock. + */ + mutex_lock(&cam->s_mutex); + cam->pix_format = fmt->fmt.pix; + cam->mbus_code = f->mbus_code; + + /* + * Make sure we have appropriate DMA buffers. + */ + if (cam->buffer_mode == B_vmalloc) { + ret = mcam_check_dma_buffers(cam); + if (ret) + goto out; + } + mcam_set_config_needed(cam, 1); + ret = 0; +out: + mutex_unlock(&cam->s_mutex); + return ret; +} + +/* + * Return our stored notion of how the camera is/should be configured. + * The V4l2 spec wants us to be smarter, and actually get this from + * the camera (and not mess with it at open time). Someday. + */ +static int mcam_vidioc_g_fmt_vid_cap(struct file *filp, void *priv, + struct v4l2_format *f) +{ + struct mcam_camera *cam = priv; + + f->fmt.pix = cam->pix_format; + return 0; +} + +/* + * We only have one input - the sensor - so minimize the nonsense here. + */ +static int mcam_vidioc_enum_input(struct file *filp, void *priv, + struct v4l2_input *input) +{ + if (input->index != 0) + return -EINVAL; + + input->type = V4L2_INPUT_TYPE_CAMERA; + input->std = V4L2_STD_ALL; /* Not sure what should go here */ + strcpy(input->name, "Camera"); + return 0; +} + +static int mcam_vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int mcam_vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + if (i != 0) + return -EINVAL; + return 0; +} + +/* from vivi.c */ +static int mcam_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a) +{ + return 0; +} + +/* + * G/S_PARM. Most of this is done by the sensor, but we are + * the level which controls the number of read buffers. + */ +static int mcam_vidioc_g_parm(struct file *filp, void *priv, + struct v4l2_streamparm *parms) +{ + struct mcam_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = sensor_call(cam, video, g_parm, parms); + mutex_unlock(&cam->s_mutex); + parms->parm.capture.readbuffers = n_dma_bufs; + return ret; +} + +static int mcam_vidioc_s_parm(struct file *filp, void *priv, + struct v4l2_streamparm *parms) +{ + struct mcam_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = sensor_call(cam, video, s_parm, parms); + mutex_unlock(&cam->s_mutex); + parms->parm.capture.readbuffers = n_dma_bufs; + return ret; +} + +static int mcam_vidioc_g_chip_ident(struct file *file, void *priv, + struct v4l2_dbg_chip_ident *chip) +{ + struct mcam_camera *cam = priv; + + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (v4l2_chip_match_host(&chip->match)) { + chip->ident = cam->chip_id; + return 0; + } + return sensor_call(cam, core, g_chip_ident, chip); +} + +static int mcam_vidioc_enum_framesizes(struct file *filp, void *priv, + struct v4l2_frmsizeenum *sizes) +{ + struct mcam_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = sensor_call(cam, video, enum_framesizes, sizes); + mutex_unlock(&cam->s_mutex); + return ret; +} + +static int mcam_vidioc_enum_frameintervals(struct file *filp, void *priv, + struct v4l2_frmivalenum *interval) +{ + struct mcam_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = sensor_call(cam, video, enum_frameintervals, interval); + mutex_unlock(&cam->s_mutex); + return ret; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int mcam_vidioc_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct mcam_camera *cam = priv; + + if (v4l2_chip_match_host(®->match)) { + reg->val = mcam_reg_read(cam, reg->reg); + reg->size = 4; + return 0; + } + return sensor_call(cam, core, g_register, reg); +} + +static int mcam_vidioc_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct mcam_camera *cam = priv; + + if (v4l2_chip_match_host(®->match)) { + mcam_reg_write(cam, reg->reg, reg->val); + return 0; + } + return sensor_call(cam, core, s_register, reg); +} +#endif + +static const struct v4l2_ioctl_ops mcam_v4l_ioctl_ops = { + .vidioc_querycap = mcam_vidioc_querycap, + .vidioc_enum_fmt_vid_cap = mcam_vidioc_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = mcam_vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = mcam_vidioc_s_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = mcam_vidioc_g_fmt_vid_cap, + .vidioc_enum_input = mcam_vidioc_enum_input, + .vidioc_g_input = mcam_vidioc_g_input, + .vidioc_s_input = mcam_vidioc_s_input, + .vidioc_s_std = mcam_vidioc_s_std, + .vidioc_reqbufs = mcam_vidioc_reqbufs, + .vidioc_querybuf = mcam_vidioc_querybuf, + .vidioc_qbuf = mcam_vidioc_qbuf, + .vidioc_dqbuf = mcam_vidioc_dqbuf, + .vidioc_streamon = mcam_vidioc_streamon, + .vidioc_streamoff = mcam_vidioc_streamoff, + .vidioc_queryctrl = mcam_vidioc_queryctrl, + .vidioc_g_ctrl = mcam_vidioc_g_ctrl, + .vidioc_s_ctrl = mcam_vidioc_s_ctrl, + .vidioc_g_parm = mcam_vidioc_g_parm, + .vidioc_s_parm = mcam_vidioc_s_parm, + .vidioc_enum_framesizes = mcam_vidioc_enum_framesizes, + .vidioc_enum_frameintervals = mcam_vidioc_enum_frameintervals, + .vidioc_g_chip_ident = mcam_vidioc_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = mcam_vidioc_g_register, + .vidioc_s_register = mcam_vidioc_s_register, +#endif +}; + +/* ---------------------------------------------------------------------- */ +/* + * Our various file operations. + */ +static int mcam_v4l_open(struct file *filp) +{ + struct mcam_camera *cam = video_drvdata(filp); + int ret = 0; + + filp->private_data = cam; + + frames = singles = delivered = 0; + mutex_lock(&cam->s_mutex); + if (cam->users == 0) { + ret = mcam_setup_vb2(cam); + if (ret) + goto out; + mcam_ctlr_power_up(cam); + __mcam_cam_reset(cam); + mcam_set_config_needed(cam, 1); + } + (cam->users)++; +out: + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int mcam_v4l_release(struct file *filp) +{ + struct mcam_camera *cam = filp->private_data; + + cam_err(cam, "Release, %d frames, %d singles, %d delivered\n", frames, + singles, delivered); + mutex_lock(&cam->s_mutex); + (cam->users)--; + if (filp == cam->owner) { + mcam_ctlr_stop_dma(cam); + cam->owner = NULL; + } + if (cam->users == 0) { + mcam_cleanup_vb2(cam); + mcam_ctlr_power_down(cam); + if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read) + mcam_free_dma_bufs(cam); + } + mutex_unlock(&cam->s_mutex); + return 0; +} + +static ssize_t mcam_v4l_read(struct file *filp, + char __user *buffer, size_t len, loff_t *pos) +{ + struct mcam_camera *cam = filp->private_data; + int ret; + + mutex_lock(&cam->s_mutex); + ret = vb2_read(&cam->vb_queue, buffer, len, pos, + filp->f_flags & O_NONBLOCK); + mutex_unlock(&cam->s_mutex); + return ret; +} + + + +static unsigned int mcam_v4l_poll(struct file *filp, + struct poll_table_struct *pt) +{ + struct mcam_camera *cam = filp->private_data; + int ret; + + mutex_lock(&cam->s_mutex); + ret = vb2_poll(&cam->vb_queue, filp, pt); + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int mcam_v4l_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct mcam_camera *cam = filp->private_data; + int ret; + + mutex_lock(&cam->s_mutex); + ret = vb2_mmap(&cam->vb_queue, vma); + mutex_unlock(&cam->s_mutex); + return ret; +} + + + +static const struct v4l2_file_operations mcam_v4l_fops = { + .owner = THIS_MODULE, + .open = mcam_v4l_open, + .release = mcam_v4l_release, + .read = mcam_v4l_read, + .poll = mcam_v4l_poll, + .mmap = mcam_v4l_mmap, + .unlocked_ioctl = video_ioctl2, +}; + + +/* + * This template device holds all of those v4l2 methods; we + * clone it for specific real devices. + */ +static struct video_device mcam_v4l_template = { + .name = "mcam", + .tvnorms = V4L2_STD_NTSC_M, + .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */ + + .fops = &mcam_v4l_fops, + .ioctl_ops = &mcam_v4l_ioctl_ops, + .release = video_device_release_empty, +}; + +/* ---------------------------------------------------------------------- */ +/* + * Interrupt handler stuff + */ +static void mcam_frame_complete(struct mcam_camera *cam, int frame) +{ + /* + * Basic frame housekeeping. + */ + set_bit(frame, &cam->flags); + clear_bit(CF_DMA_ACTIVE, &cam->flags); + cam->next_buf = frame; + cam->buf_seq[frame] = ++(cam->sequence); + frames++; + /* + * "This should never happen" + */ + if (cam->state != S_STREAMING) + return; + /* + * Process the frame and set up the next one. + */ + cam->frame_complete(cam, frame); +} + + +/* + * The interrupt handler; this needs to be called from the + * platform irq handler with the lock held. + */ +int mccic_irq(struct mcam_camera *cam, unsigned int irqs) +{ + unsigned int frame, handled = 0; + + mcam_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */ + /* + * Handle any frame completions. There really should + * not be more than one of these, or we have fallen + * far behind. + * + * When running in S/G mode, the frame number lacks any + * real meaning - there's only one descriptor array - but + * the controller still picks a different one to signal + * each time. + */ + for (frame = 0; frame < cam->nbufs; frame++) + if (irqs & (IRQ_EOF0 << frame)) { + mcam_frame_complete(cam, frame); + handled = 1; + } + /* + * If a frame starts, note that we have DMA active. This + * code assumes that we won't get multiple frame interrupts + * at once; may want to rethink that. + */ + if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2)) { + set_bit(CF_DMA_ACTIVE, &cam->flags); + handled = 1; + if (cam->buffer_mode == B_DMA_sg) + mcam_ctlr_stop(cam); + } + return handled; +} + +/* ---------------------------------------------------------------------- */ +/* + * Registration and such. + */ +static struct ov7670_config sensor_cfg = { + /* + * Exclude QCIF mode, because it only captures a tiny portion + * of the sensor FOV + */ + .min_width = 320, + .min_height = 240, +}; + + +int mccic_register(struct mcam_camera *cam) +{ + struct i2c_board_info ov7670_info = { + .type = "ov7670", + .addr = 0x42 >> 1, + .platform_data = &sensor_cfg, + }; + int ret; + + /* + * Validate the requested buffer mode. + */ + if (buffer_mode >= 0) + cam->buffer_mode = buffer_mode; + if (cam->buffer_mode == B_DMA_sg && + cam->chip_id == V4L2_IDENT_CAFE) { + printk(KERN_ERR "marvell-cam: Cafe can't do S/G I/O, " + "attempting vmalloc mode instead\n"); + cam->buffer_mode = B_vmalloc; + } + if (!mcam_buffer_mode_supported(cam->buffer_mode)) { + printk(KERN_ERR "marvell-cam: buffer mode %d unsupported\n", + cam->buffer_mode); + return -EINVAL; + } + /* + * Register with V4L + */ + ret = v4l2_device_register(cam->dev, &cam->v4l2_dev); + if (ret) + return ret; + + mutex_init(&cam->s_mutex); + cam->state = S_NOTREADY; + mcam_set_config_needed(cam, 1); + cam->pix_format = mcam_def_pix_format; + cam->mbus_code = mcam_def_mbus_code; + INIT_LIST_HEAD(&cam->buffers); + mcam_ctlr_init(cam); + + /* + * Try to find the sensor. + */ + sensor_cfg.clock_speed = cam->clock_speed; + sensor_cfg.use_smbus = cam->use_smbus; + cam->sensor_addr = ov7670_info.addr; + cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, + cam->i2c_adapter, &ov7670_info, NULL); + if (cam->sensor == NULL) { + ret = -ENODEV; + goto out_unregister; + } + + ret = mcam_cam_init(cam); + if (ret) + goto out_unregister; + /* + * Get the v4l2 setup done. + */ + mutex_lock(&cam->s_mutex); + cam->vdev = mcam_v4l_template; + cam->vdev.debug = 0; + cam->vdev.v4l2_dev = &cam->v4l2_dev; + ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); + if (ret) + goto out; + video_set_drvdata(&cam->vdev, cam); + + /* + * If so requested, try to get our DMA buffers now. + */ + if (cam->buffer_mode == B_vmalloc && !alloc_bufs_at_read) { + if (mcam_alloc_dma_bufs(cam, 1)) + cam_warn(cam, "Unable to alloc DMA buffers at load" + " will try again later."); + } + +out: + mutex_unlock(&cam->s_mutex); + return ret; +out_unregister: + v4l2_device_unregister(&cam->v4l2_dev); + return ret; +} + + +void mccic_shutdown(struct mcam_camera *cam) +{ + /* + * If we have no users (and we really, really should have no + * users) the device will already be powered down. Trying to + * take it down again will wedge the machine, which is frowned + * upon. + */ + if (cam->users > 0) { + cam_warn(cam, "Removing a device with users!\n"); + mcam_ctlr_power_down(cam); + } + vb2_queue_release(&cam->vb_queue); + if (cam->buffer_mode == B_vmalloc) + mcam_free_dma_bufs(cam); + video_unregister_device(&cam->vdev); + v4l2_device_unregister(&cam->v4l2_dev); +} + +/* + * Power management + */ +#ifdef CONFIG_PM + +void mccic_suspend(struct mcam_camera *cam) +{ + enum mcam_state cstate = cam->state; + + mcam_ctlr_stop_dma(cam); + mcam_ctlr_power_down(cam); + cam->state = cstate; +} + +int mccic_resume(struct mcam_camera *cam) +{ + int ret = 0; + + mutex_lock(&cam->s_mutex); + if (cam->users > 0) { + mcam_ctlr_power_up(cam); + __mcam_cam_reset(cam); + } else { + mcam_ctlr_power_down(cam); + } + mutex_unlock(&cam->s_mutex); + + set_bit(CF_CONFIG_NEEDED, &cam->flags); + if (cam->state == S_STREAMING) + ret = mcam_read_setup(cam); + return ret; +} +#endif /* CONFIG_PM */ diff --git a/drivers/media/video/marvell-ccic/mcam-core.h b/drivers/media/video/marvell-ccic/mcam-core.h new file mode 100644 index 0000000000000000000000000000000000000000..917200e63255d2ee5b778edb71da245076910619 --- /dev/null +++ b/drivers/media/video/marvell-ccic/mcam-core.h @@ -0,0 +1,323 @@ +/* + * Marvell camera core structures. + * + * Copyright 2011 Jonathan Corbet corbet@lwn.net + */ +#ifndef _MCAM_CORE_H +#define _MCAM_CORE_H + +#include +#include +#include +#include + +/* + * Create our own symbols for the supported buffer modes, but, for now, + * base them entirely on which videobuf2 options have been selected. + */ +#if defined(CONFIG_VIDEOBUF2_VMALLOC) || defined(CONFIG_VIDEOBUF2_VMALLOC_MODULE) +#define MCAM_MODE_VMALLOC 1 +#endif + +#if defined(CONFIG_VIDEOBUF2_DMA_CONTIG) || defined(CONFIG_VIDEOBUF2_DMA_CONTIG_MODULE) +#define MCAM_MODE_DMA_CONTIG 1 +#endif + +#if defined(CONFIG_VIDEOBUF2_DMA_SG) || defined(CONFIG_VIDEOBUF2_DMA_SG_MODULE) +#define MCAM_MODE_DMA_SG 1 +#endif + +#if !defined(MCAM_MODE_VMALLOC) && !defined(MCAM_MODE_DMA_CONTIG) && \ + !defined(MCAM_MODE_DMA_SG) +#error One of the videobuf buffer modes must be selected in the config +#endif + + +enum mcam_state { + S_NOTREADY, /* Not yet initialized */ + S_IDLE, /* Just hanging around */ + S_FLAKED, /* Some sort of problem */ + S_STREAMING, /* Streaming data */ + S_BUFWAIT /* streaming requested but no buffers yet */ +}; +#define MAX_DMA_BUFS 3 + +/* + * Different platforms work best with different buffer modes, so we + * let the platform pick. + */ +enum mcam_buffer_mode { + B_vmalloc = 0, + B_DMA_contig = 1, + B_DMA_sg = 2 +}; + +/* + * Is a given buffer mode supported by the current kernel configuration? + */ +static inline int mcam_buffer_mode_supported(enum mcam_buffer_mode mode) +{ + switch (mode) { +#ifdef MCAM_MODE_VMALLOC + case B_vmalloc: +#endif +#ifdef MCAM_MODE_DMA_CONTIG + case B_DMA_contig: +#endif +#ifdef MCAM_MODE_DMA_SG + case B_DMA_sg: +#endif + return 1; + default: + return 0; + } +} + + +/* + * A description of one of our devices. + * Locking: controlled by s_mutex. Certain fields, however, require + * the dev_lock spinlock; they are marked as such by comments. + * dev_lock is also required for access to device registers. + */ +struct mcam_camera { + /* + * These fields should be set by the platform code prior to + * calling mcam_register(). + */ + struct i2c_adapter *i2c_adapter; + unsigned char __iomem *regs; + spinlock_t dev_lock; + struct device *dev; /* For messages, dma alloc */ + unsigned int chip_id; + short int clock_speed; /* Sensor clock speed, default 30 */ + short int use_smbus; /* SMBUS or straight I2c? */ + enum mcam_buffer_mode buffer_mode; + /* + * Callbacks from the core to the platform code. + */ + void (*plat_power_up) (struct mcam_camera *cam); + void (*plat_power_down) (struct mcam_camera *cam); + + /* + * Everything below here is private to the mcam core and + * should not be touched by the platform code. + */ + struct v4l2_device v4l2_dev; + enum mcam_state state; + unsigned long flags; /* Buffer status, mainly (dev_lock) */ + int users; /* How many open FDs */ + struct file *owner; /* Who has data access (v4l2) */ + + /* + * Subsystem structures. + */ + struct video_device vdev; + struct v4l2_subdev *sensor; + unsigned short sensor_addr; + + /* Videobuf2 stuff */ + struct vb2_queue vb_queue; + struct list_head buffers; /* Available frames */ + + unsigned int nbufs; /* How many are alloc'd */ + int next_buf; /* Next to consume (dev_lock) */ + + /* DMA buffers - vmalloc mode */ +#ifdef MCAM_MODE_VMALLOC + unsigned int dma_buf_size; /* allocated size */ + void *dma_bufs[MAX_DMA_BUFS]; /* Internal buffer addresses */ + dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */ + struct tasklet_struct s_tasklet; +#endif + unsigned int sequence; /* Frame sequence number */ + unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual bufs */ + + /* DMA buffers - DMA modes */ + struct mcam_vb_buffer *vb_bufs[MAX_DMA_BUFS]; + struct vb2_alloc_ctx *vb_alloc_ctx; + + /* Mode-specific ops, set at open time */ + void (*dma_setup)(struct mcam_camera *cam); + void (*frame_complete)(struct mcam_camera *cam, int frame); + + /* Current operating parameters */ + u32 sensor_type; /* Currently ov7670 only */ + struct v4l2_pix_format pix_format; + enum v4l2_mbus_pixelcode mbus_code; + + /* Locks */ + struct mutex s_mutex; /* Access to this structure */ +}; + + +/* + * Register I/O functions. These are here because the platform code + * may legitimately need to mess with the register space. + */ +/* + * Device register I/O + */ +static inline void mcam_reg_write(struct mcam_camera *cam, unsigned int reg, + unsigned int val) +{ + iowrite32(val, cam->regs + reg); +} + +static inline unsigned int mcam_reg_read(struct mcam_camera *cam, + unsigned int reg) +{ + return ioread32(cam->regs + reg); +} + + +static inline void mcam_reg_write_mask(struct mcam_camera *cam, unsigned int reg, + unsigned int val, unsigned int mask) +{ + unsigned int v = mcam_reg_read(cam, reg); + + v = (v & ~mask) | (val & mask); + mcam_reg_write(cam, reg, v); +} + +static inline void mcam_reg_clear_bit(struct mcam_camera *cam, + unsigned int reg, unsigned int val) +{ + mcam_reg_write_mask(cam, reg, 0, val); +} + +static inline void mcam_reg_set_bit(struct mcam_camera *cam, + unsigned int reg, unsigned int val) +{ + mcam_reg_write_mask(cam, reg, val, val); +} + +/* + * Functions for use by platform code. + */ +int mccic_register(struct mcam_camera *cam); +int mccic_irq(struct mcam_camera *cam, unsigned int irqs); +void mccic_shutdown(struct mcam_camera *cam); +#ifdef CONFIG_PM +void mccic_suspend(struct mcam_camera *cam); +int mccic_resume(struct mcam_camera *cam); +#endif + +/* + * Register definitions for the m88alp01 camera interface. Offsets in bytes + * as given in the spec. + */ +#define REG_Y0BAR 0x00 +#define REG_Y1BAR 0x04 +#define REG_Y2BAR 0x08 +/* ... */ + +#define REG_IMGPITCH 0x24 /* Image pitch register */ +#define IMGP_YP_SHFT 2 /* Y pitch params */ +#define IMGP_YP_MASK 0x00003ffc /* Y pitch field */ +#define IMGP_UVP_SHFT 18 /* UV pitch (planar) */ +#define IMGP_UVP_MASK 0x3ffc0000 +#define REG_IRQSTATRAW 0x28 /* RAW IRQ Status */ +#define IRQ_EOF0 0x00000001 /* End of frame 0 */ +#define IRQ_EOF1 0x00000002 /* End of frame 1 */ +#define IRQ_EOF2 0x00000004 /* End of frame 2 */ +#define IRQ_SOF0 0x00000008 /* Start of frame 0 */ +#define IRQ_SOF1 0x00000010 /* Start of frame 1 */ +#define IRQ_SOF2 0x00000020 /* Start of frame 2 */ +#define IRQ_OVERFLOW 0x00000040 /* FIFO overflow */ +#define IRQ_TWSIW 0x00010000 /* TWSI (smbus) write */ +#define IRQ_TWSIR 0x00020000 /* TWSI read */ +#define IRQ_TWSIE 0x00040000 /* TWSI error */ +#define TWSIIRQS (IRQ_TWSIW|IRQ_TWSIR|IRQ_TWSIE) +#define FRAMEIRQS (IRQ_EOF0|IRQ_EOF1|IRQ_EOF2|IRQ_SOF0|IRQ_SOF1|IRQ_SOF2) +#define ALLIRQS (TWSIIRQS|FRAMEIRQS|IRQ_OVERFLOW) +#define REG_IRQMASK 0x2c /* IRQ mask - same bits as IRQSTAT */ +#define REG_IRQSTAT 0x30 /* IRQ status / clear */ + +#define REG_IMGSIZE 0x34 /* Image size */ +#define IMGSZ_V_MASK 0x1fff0000 +#define IMGSZ_V_SHIFT 16 +#define IMGSZ_H_MASK 0x00003fff +#define REG_IMGOFFSET 0x38 /* IMage offset */ + +#define REG_CTRL0 0x3c /* Control 0 */ +#define C0_ENABLE 0x00000001 /* Makes the whole thing go */ + +/* Mask for all the format bits */ +#define C0_DF_MASK 0x00fffffc /* Bits 2-23 */ + +/* RGB ordering */ +#define C0_RGB4_RGBX 0x00000000 +#define C0_RGB4_XRGB 0x00000004 +#define C0_RGB4_BGRX 0x00000008 +#define C0_RGB4_XBGR 0x0000000c +#define C0_RGB5_RGGB 0x00000000 +#define C0_RGB5_GRBG 0x00000004 +#define C0_RGB5_GBRG 0x00000008 +#define C0_RGB5_BGGR 0x0000000c + +/* Spec has two fields for DIN and DOUT, but they must match, so + combine them here. */ +#define C0_DF_YUV 0x00000000 /* Data is YUV */ +#define C0_DF_RGB 0x000000a0 /* ... RGB */ +#define C0_DF_BAYER 0x00000140 /* ... Bayer */ +/* 8-8-8 must be missing from the below - ask */ +#define C0_RGBF_565 0x00000000 +#define C0_RGBF_444 0x00000800 +#define C0_RGB_BGR 0x00001000 /* Blue comes first */ +#define C0_YUV_PLANAR 0x00000000 /* YUV 422 planar format */ +#define C0_YUV_PACKED 0x00008000 /* YUV 422 packed */ +#define C0_YUV_420PL 0x0000a000 /* YUV 420 planar */ +/* Think that 420 packed must be 111 - ask */ +#define C0_YUVE_YUYV 0x00000000 /* Y1CbY0Cr */ +#define C0_YUVE_YVYU 0x00010000 /* Y1CrY0Cb */ +#define C0_YUVE_VYUY 0x00020000 /* CrY1CbY0 */ +#define C0_YUVE_UYVY 0x00030000 /* CbY1CrY0 */ +#define C0_YUVE_XYUV 0x00000000 /* 420: .YUV */ +#define C0_YUVE_XYVU 0x00010000 /* 420: .YVU */ +#define C0_YUVE_XUVY 0x00020000 /* 420: .UVY */ +#define C0_YUVE_XVUY 0x00030000 /* 420: .VUY */ +/* Bayer bits 18,19 if needed */ +#define C0_HPOL_LOW 0x01000000 /* HSYNC polarity active low */ +#define C0_VPOL_LOW 0x02000000 /* VSYNC polarity active low */ +#define C0_VCLK_LOW 0x04000000 /* VCLK on falling edge */ +#define C0_DOWNSCALE 0x08000000 /* Enable downscaler */ +#define C0_SIFM_MASK 0xc0000000 /* SIF mode bits */ +#define C0_SIF_HVSYNC 0x00000000 /* Use H/VSYNC */ +#define CO_SOF_NOSYNC 0x40000000 /* Use inband active signaling */ + +/* Bits below C1_444ALPHA are not present in Cafe */ +#define REG_CTRL1 0x40 /* Control 1 */ +#define C1_CLKGATE 0x00000001 /* Sensor clock gate */ +#define C1_DESC_ENA 0x00000100 /* DMA descriptor enable */ +#define C1_DESC_3WORD 0x00000200 /* Three-word descriptors used */ +#define C1_444ALPHA 0x00f00000 /* Alpha field in RGB444 */ +#define C1_ALPHA_SHFT 20 +#define C1_DMAB32 0x00000000 /* 32-byte DMA burst */ +#define C1_DMAB16 0x02000000 /* 16-byte DMA burst */ +#define C1_DMAB64 0x04000000 /* 64-byte DMA burst */ +#define C1_DMAB_MASK 0x06000000 +#define C1_TWOBUFS 0x08000000 /* Use only two DMA buffers */ +#define C1_PWRDWN 0x10000000 /* Power down */ + +#define REG_CLKCTRL 0x88 /* Clock control */ +#define CLK_DIV_MASK 0x0000ffff /* Upper bits RW "reserved" */ + +/* This appears to be a Cafe-only register */ +#define REG_UBAR 0xc4 /* Upper base address register */ + +/* Armada 610 DMA descriptor registers */ +#define REG_DMA_DESC_Y 0x200 +#define REG_DMA_DESC_U 0x204 +#define REG_DMA_DESC_V 0x208 +#define REG_DESC_LEN_Y 0x20c /* Lengths are in bytes */ +#define REG_DESC_LEN_U 0x210 +#define REG_DESC_LEN_V 0x214 + +/* + * Useful stuff that probably belongs somewhere global. + */ +#define VGA_WIDTH 640 +#define VGA_HEIGHT 480 + +#endif /* _MCAM_CORE_H */ diff --git a/drivers/media/video/marvell-ccic/mmp-driver.c b/drivers/media/video/marvell-ccic/mmp-driver.c new file mode 100644 index 0000000000000000000000000000000000000000..d6b764541375ef0f0076988e6809375af2f2686f --- /dev/null +++ b/drivers/media/video/marvell-ccic/mmp-driver.c @@ -0,0 +1,340 @@ +/* + * Support for the camera device found on Marvell MMP processors; known + * to work with the Armada 610 as used in the OLPC 1.75 system. + * + * Copyright 2011 Jonathan Corbet + * + * This file may be distributed under the terms of the GNU General + * Public License, version 2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mcam-core.h" + +MODULE_AUTHOR("Jonathan Corbet "); +MODULE_LICENSE("GPL"); + +struct mmp_camera { + void *power_regs; + struct platform_device *pdev; + struct mcam_camera mcam; + struct list_head devlist; + int irq; +}; + +static inline struct mmp_camera *mcam_to_cam(struct mcam_camera *mcam) +{ + return container_of(mcam, struct mmp_camera, mcam); +} + +/* + * A silly little infrastructure so we can keep track of our devices. + * Chances are that we will never have more than one of them, but + * the Armada 610 *does* have two controllers... + */ + +static LIST_HEAD(mmpcam_devices); +static struct mutex mmpcam_devices_lock; + +static void mmpcam_add_device(struct mmp_camera *cam) +{ + mutex_lock(&mmpcam_devices_lock); + list_add(&cam->devlist, &mmpcam_devices); + mutex_unlock(&mmpcam_devices_lock); +} + +static void mmpcam_remove_device(struct mmp_camera *cam) +{ + mutex_lock(&mmpcam_devices_lock); + list_del(&cam->devlist); + mutex_unlock(&mmpcam_devices_lock); +} + +/* + * Platform dev remove passes us a platform_device, and there's + * no handy unused drvdata to stash a backpointer in. So just + * dig it out of our list. + */ +static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev) +{ + struct mmp_camera *cam; + + mutex_lock(&mmpcam_devices_lock); + list_for_each_entry(cam, &mmpcam_devices, devlist) { + if (cam->pdev == pdev) { + mutex_unlock(&mmpcam_devices_lock); + return cam; + } + } + mutex_unlock(&mmpcam_devices_lock); + return NULL; +} + + + + +/* + * Power-related registers; this almost certainly belongs + * somewhere else. + * + * ARMADA 610 register manual, sec 7.2.1, p1842. + */ +#define CPU_SUBSYS_PMU_BASE 0xd4282800 +#define REG_CCIC_DCGCR 0x28 /* CCIC dyn clock gate ctrl reg */ +#define REG_CCIC_CRCR 0x50 /* CCIC clk reset ctrl reg */ + +/* + * Power control. + */ +static void mmpcam_power_up(struct mcam_camera *mcam) +{ + struct mmp_camera *cam = mcam_to_cam(mcam); + struct mmp_camera_platform_data *pdata; +/* + * Turn on power and clocks to the controller. + */ + iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR); + iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR); + mdelay(1); +/* + * Provide power to the sensor. + */ + mcam_reg_write(mcam, REG_CLKCTRL, 0x60000002); + pdata = cam->pdev->dev.platform_data; + gpio_set_value(pdata->sensor_power_gpio, 1); + mdelay(5); + mcam_reg_clear_bit(mcam, REG_CTRL1, 0x10000000); + gpio_set_value(pdata->sensor_reset_gpio, 0); /* reset is active low */ + mdelay(5); + gpio_set_value(pdata->sensor_reset_gpio, 1); /* reset is active low */ + mdelay(5); +} + +static void mmpcam_power_down(struct mcam_camera *mcam) +{ + struct mmp_camera *cam = mcam_to_cam(mcam); + struct mmp_camera_platform_data *pdata; +/* + * Turn off clocks and set reset lines + */ + iowrite32(0, cam->power_regs + REG_CCIC_DCGCR); + iowrite32(0, cam->power_regs + REG_CCIC_CRCR); +/* + * Shut down the sensor. + */ + pdata = cam->pdev->dev.platform_data; + gpio_set_value(pdata->sensor_power_gpio, 0); + gpio_set_value(pdata->sensor_reset_gpio, 0); +} + + +static irqreturn_t mmpcam_irq(int irq, void *data) +{ + struct mcam_camera *mcam = data; + unsigned int irqs, handled; + + spin_lock(&mcam->dev_lock); + irqs = mcam_reg_read(mcam, REG_IRQSTAT); + handled = mccic_irq(mcam, irqs); + spin_unlock(&mcam->dev_lock); + return IRQ_RETVAL(handled); +} + + +static int mmpcam_probe(struct platform_device *pdev) +{ + struct mmp_camera *cam; + struct mcam_camera *mcam; + struct resource *res; + struct mmp_camera_platform_data *pdata; + int ret; + + cam = kzalloc(sizeof(*cam), GFP_KERNEL); + if (cam == NULL) + return -ENOMEM; + cam->pdev = pdev; + INIT_LIST_HEAD(&cam->devlist); + + mcam = &cam->mcam; + mcam->platform = MHP_Armada610; + mcam->plat_power_up = mmpcam_power_up; + mcam->plat_power_down = mmpcam_power_down; + mcam->dev = &pdev->dev; + mcam->use_smbus = 0; + mcam->chip_id = V4L2_IDENT_ARMADA610; + mcam->buffer_mode = B_DMA_sg; + spin_lock_init(&mcam->dev_lock); + /* + * Get our I/O memory. + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no iomem resource!\n"); + ret = -ENODEV; + goto out_free; + } + mcam->regs = ioremap(res->start, resource_size(res)); + if (mcam->regs == NULL) { + dev_err(&pdev->dev, "MMIO ioremap fail\n"); + ret = -ENODEV; + goto out_free; + } + /* + * Power/clock memory is elsewhere; get it too. Perhaps this + * should really be managed outside of this driver? + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res == NULL) { + dev_err(&pdev->dev, "no power resource!\n"); + ret = -ENODEV; + goto out_unmap1; + } + cam->power_regs = ioremap(res->start, resource_size(res)); + if (cam->power_regs == NULL) { + dev_err(&pdev->dev, "power MMIO ioremap fail\n"); + ret = -ENODEV; + goto out_unmap1; + } + /* + * Find the i2c adapter. This assumes, of course, that the + * i2c bus is already up and functioning. + */ + pdata = pdev->dev.platform_data; + mcam->i2c_adapter = platform_get_drvdata(pdata->i2c_device); + if (mcam->i2c_adapter == NULL) { + ret = -ENODEV; + dev_err(&pdev->dev, "No i2c adapter\n"); + goto out_unmap2; + } + /* + * Sensor GPIO pins. + */ + ret = gpio_request(pdata->sensor_power_gpio, "cam-power"); + if (ret) { + dev_err(&pdev->dev, "Can't get sensor power gpio %d", + pdata->sensor_power_gpio); + goto out_unmap2; + } + gpio_direction_output(pdata->sensor_power_gpio, 0); + ret = gpio_request(pdata->sensor_reset_gpio, "cam-reset"); + if (ret) { + dev_err(&pdev->dev, "Can't get sensor reset gpio %d", + pdata->sensor_reset_gpio); + goto out_gpio; + } + gpio_direction_output(pdata->sensor_reset_gpio, 0); + /* + * Power the device up and hand it off to the core. + */ + mmpcam_power_up(mcam); + ret = mccic_register(mcam); + if (ret) + goto out_gpio2; + /* + * Finally, set up our IRQ now that the core is ready to + * deal with it. + */ + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res == NULL) { + ret = -ENODEV; + goto out_unregister; + } + cam->irq = res->start; + ret = request_irq(cam->irq, mmpcam_irq, IRQF_SHARED, + "mmp-camera", mcam); + if (ret == 0) { + mmpcam_add_device(cam); + return 0; + } + +out_unregister: + mccic_shutdown(mcam); +out_gpio2: + mmpcam_power_down(mcam); + gpio_free(pdata->sensor_reset_gpio); +out_gpio: + gpio_free(pdata->sensor_power_gpio); +out_unmap2: + iounmap(cam->power_regs); +out_unmap1: + iounmap(mcam->regs); +out_free: + kfree(cam); + return ret; +} + + +static int mmpcam_remove(struct mmp_camera *cam) +{ + struct mcam_camera *mcam = &cam->mcam; + struct mmp_camera_platform_data *pdata; + + mmpcam_remove_device(cam); + free_irq(cam->irq, mcam); + mccic_shutdown(mcam); + mmpcam_power_down(mcam); + pdata = cam->pdev->dev.platform_data; + gpio_free(pdata->sensor_reset_gpio); + gpio_free(pdata->sensor_power_gpio); + iounmap(cam->power_regs); + iounmap(mcam->regs); + kfree(cam); + return 0; +} + +static int mmpcam_platform_remove(struct platform_device *pdev) +{ + struct mmp_camera *cam = mmpcam_find_device(pdev); + + if (cam == NULL) + return -ENODEV; + return mmpcam_remove(cam); +} + + +static struct platform_driver mmpcam_driver = { + .probe = mmpcam_probe, + .remove = mmpcam_platform_remove, + .driver = { + .name = "mmp-camera", + .owner = THIS_MODULE + } +}; + + +static int __init mmpcam_init_module(void) +{ + mutex_init(&mmpcam_devices_lock); + return platform_driver_register(&mmpcam_driver); +} + +static void __exit mmpcam_exit_module(void) +{ + platform_driver_unregister(&mmpcam_driver); + /* + * platform_driver_unregister() should have emptied the list + */ + if (!list_empty(&mmpcam_devices)) + printk(KERN_ERR "mmp_camera leaving devices behind\n"); +} + +module_init(mmpcam_init_module); +module_exit(mmpcam_exit_module); diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c index b03d74e09a3c1083f226942e7b82f708797a38fc..166bf9349c10c03dacce418f452e7bdc64df168a 100644 --- a/drivers/media/video/mem2mem_testdev.c +++ b/drivers/media/video/mem2mem_testdev.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -35,7 +34,7 @@ MODULE_DESCRIPTION("Virtual device for mem2mem framework testing"); MODULE_AUTHOR("Pawel Osciak, "); MODULE_LICENSE("GPL"); - +MODULE_VERSION("0.1.1"); #define MIN_W 32 #define MIN_H 32 @@ -380,7 +379,6 @@ static int vidioc_querycap(struct file *file, void *priv, strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); cap->bus_info[0] = 0; - cap->version = KERNEL_VERSION(0, 1, 0); cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index e2bbd8c35c9860a9ad1bd16d0ded17df64fae1ca..4da9cca939c121999908d021d66d169a20df70b7 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -603,13 +603,9 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, unsigned long flags; int ret; - /* - * We must have a parent by now. And it cannot be a wrong one. - * So this entire test is completely redundant. - */ - if (!icd->dev.parent || - to_soc_camera_host(icd->dev.parent)->nr != icd->iface) - return -ENODEV; + /* We must have a parent by now. And it cannot be a wrong one. */ + BUG_ON(!icd->parent || + to_soc_camera_host(icd->parent)->nr != icd->iface); /* Enable the chip */ data = reg_write(client, MT9M001_CHIP_ENABLE, 1); @@ -675,8 +671,8 @@ static void mt9m001_video_remove(struct soc_camera_device *icd) { struct soc_camera_link *icl = to_soc_camera_link(icd); - dev_dbg(&icd->dev, "Video removed: %p, %p\n", - icd->dev.parent, icd->vdev); + dev_dbg(icd->pdev, "Video removed: %p, %p\n", + icd->parent, icd->vdev); if (icl->free_bus) icl->free_bus(icl); } diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index ebebed929627c8a8ffcae19a6730992a066c0372..a357aa889fc6c07357b91c86877f8094db7d8539 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -63,6 +63,12 @@ #define MT9M111_RESET_RESTART_FRAME (1 << 1) #define MT9M111_RESET_RESET_MODE (1 << 0) +#define MT9M111_RM_FULL_POWER_RD (0 << 10) +#define MT9M111_RM_LOW_POWER_RD (1 << 10) +#define MT9M111_RM_COL_SKIP_4X (1 << 5) +#define MT9M111_RM_ROW_SKIP_4X (1 << 4) +#define MT9M111_RM_COL_SKIP_2X (1 << 3) +#define MT9M111_RM_ROW_SKIP_2X (1 << 2) #define MT9M111_RMB_MIRROR_COLS (1 << 1) #define MT9M111_RMB_MIRROR_ROWS (1 << 0) #define MT9M111_CTXT_CTRL_RESTART (1 << 15) @@ -95,7 +101,8 @@ #define MT9M111_OPMODE_AUTOEXPO_EN (1 << 14) #define MT9M111_OPMODE_AUTOWHITEBAL_EN (1 << 1) - +#define MT9M111_OUTFMT_FLIP_BAYER_COL (1 << 9) +#define MT9M111_OUTFMT_FLIP_BAYER_ROW (1 << 8) #define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14) #define MT9M111_OUTFMT_BYPASS_IFP (1 << 10) #define MT9M111_OUTFMT_INV_PIX_CLOCK (1 << 9) @@ -110,9 +117,8 @@ #define MT9M111_OUTFMT_TST_RAMP_FRAME (3 << 4) #define MT9M111_OUTFMT_SHIFT_3_UP (1 << 3) #define MT9M111_OUTFMT_AVG_CHROMA (1 << 2) -#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y (1 << 1) -#define MT9M111_OUTFMT_SWAP_RGB_EVEN (1 << 1) -#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr (1 << 0) +#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN (1 << 1) +#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B (1 << 0) /* * Camera control register addresses (0x200..0x2ff not implemented) @@ -122,6 +128,8 @@ #define reg_write(reg, val) mt9m111_reg_write(client, MT9M111_##reg, (val)) #define reg_set(reg, val) mt9m111_reg_set(client, MT9M111_##reg, (val)) #define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val)) +#define reg_mask(reg, val, mask) mt9m111_reg_mask(client, MT9M111_##reg, \ + (val), (mask)) #define MT9M111_MIN_DARK_ROWS 8 #define MT9M111_MIN_DARK_COLS 26 @@ -153,7 +161,11 @@ static const struct mt9m111_datafmt mt9m111_colour_fmts[] = { {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG}, {V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG}, {V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB}, {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_BGR565_2X8_LE, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_BGR565_2X8_BE, V4L2_COLORSPACE_SRGB}, {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, }; @@ -169,6 +181,8 @@ struct mt9m111 { * from v4l2-chip-ident.h */ enum mt9m111_context context; struct v4l2_rect rect; + struct mutex power_lock; /* lock to protect power_count */ + int power_count; const struct mt9m111_datafmt *fmt; unsigned int gain; unsigned char autoexposure; @@ -176,10 +190,6 @@ struct mt9m111 { unsigned int powered:1; unsigned int hflip:1; unsigned int vflip:1; - unsigned int swap_rgb_even_odd:1; - unsigned int swap_rgb_red_blue:1; - unsigned int swap_yuv_y_chromas:1; - unsigned int swap_yuv_cb_cr:1; unsigned int autowhitebalance:1; }; @@ -248,12 +258,26 @@ static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg, int ret; ret = mt9m111_reg_read(client, reg); - return mt9m111_reg_write(client, reg, ret & ~data); + if (ret >= 0) + ret = mt9m111_reg_write(client, reg, ret & ~data); + return ret; } -static int mt9m111_set_context(struct i2c_client *client, +static int mt9m111_reg_mask(struct i2c_client *client, const u16 reg, + const u16 data, const u16 mask) +{ + int ret; + + ret = mt9m111_reg_read(client, reg); + if (ret >= 0) + ret = mt9m111_reg_write(client, reg, (ret & ~mask) | data); + return ret; +} + +static int mt9m111_set_context(struct mt9m111 *mt9m111, enum mt9m111_context ctxt) { + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B @@ -267,10 +291,10 @@ static int mt9m111_set_context(struct i2c_client *client, return reg_write(CONTEXT_CONTROL, valA); } -static int mt9m111_setup_rect(struct i2c_client *client, +static int mt9m111_setup_rect(struct mt9m111 *mt9m111, struct v4l2_rect *rect) { - struct mt9m111 *mt9m111 = to_mt9m111(client); + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); int ret, is_raw_format; int width = rect->width; int height = rect->height; @@ -312,81 +336,9 @@ static int mt9m111_setup_rect(struct i2c_client *client, return ret; } -static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt) +static int mt9m111_enable(struct mt9m111 *mt9m111) { - int ret; - u16 mask = MT9M111_OUTFMT_PROCESSED_BAYER | MT9M111_OUTFMT_RGB | - MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_SWAP_RGB_EVEN | - MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 | - MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr | - MT9M111_OUTFMT_SWAP_YCbCr_C_Y; - - ret = reg_read(OUTPUT_FORMAT_CTRL2_A); - if (ret >= 0) - ret = reg_write(OUTPUT_FORMAT_CTRL2_A, (ret & ~mask) | outfmt); - if (!ret) - ret = reg_read(OUTPUT_FORMAT_CTRL2_B); - if (ret >= 0) - ret = reg_write(OUTPUT_FORMAT_CTRL2_B, (ret & ~mask) | outfmt); - - return ret; -} - -static int mt9m111_setfmt_bayer8(struct i2c_client *client) -{ - return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_PROCESSED_BAYER | - MT9M111_OUTFMT_RGB); -} - -static int mt9m111_setfmt_bayer10(struct i2c_client *client) -{ - return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_BYPASS_IFP); -} - -static int mt9m111_setfmt_rgb565(struct i2c_client *client) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - int val = 0; - - if (mt9m111->swap_rgb_red_blue) - val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr; - if (mt9m111->swap_rgb_even_odd) - val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; - val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565; - - return mt9m111_setup_pixfmt(client, val); -} - -static int mt9m111_setfmt_rgb555(struct i2c_client *client) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - int val = 0; - - if (mt9m111->swap_rgb_red_blue) - val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr; - if (mt9m111->swap_rgb_even_odd) - val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; - val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555; - - return mt9m111_setup_pixfmt(client, val); -} - -static int mt9m111_setfmt_yuv(struct i2c_client *client) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - int val = 0; - - if (mt9m111->swap_yuv_cb_cr) - val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr; - if (mt9m111->swap_yuv_y_chromas) - val |= MT9M111_OUTFMT_SWAP_YCbCr_C_Y; - - return mt9m111_setup_pixfmt(client, val); -} - -static int mt9m111_enable(struct i2c_client *client) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); int ret; ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE); @@ -395,8 +347,9 @@ static int mt9m111_enable(struct i2c_client *client) return ret; } -static int mt9m111_reset(struct i2c_client *client) +static int mt9m111_reset(struct mt9m111 *mt9m111) { + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); int ret; ret = reg_set(RESET, MT9M111_RESET_RESET_MODE); @@ -424,11 +377,9 @@ static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f) return 0; } -static int mt9m111_make_rect(struct i2c_client *client, +static int mt9m111_make_rect(struct mt9m111 *mt9m111, struct v4l2_rect *rect) { - struct mt9m111 *mt9m111 = to_mt9m111(client); - if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 || mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) { /* Bayer format - even size lengths */ @@ -444,14 +395,14 @@ static int mt9m111_make_rect(struct i2c_client *client, soc_camera_limit_side(&rect->top, &rect->height, MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT); - return mt9m111_setup_rect(client, rect); + return mt9m111_setup_rect(mt9m111, rect); } static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { struct v4l2_rect rect = a->c; struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = to_mt9m111(client); + struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); int ret; dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n", @@ -460,7 +411,7 @@ static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - ret = mt9m111_make_rect(client, &rect); + ret = mt9m111_make_rect(mt9m111, &rect); if (!ret) mt9m111->rect = rect; return ret; @@ -468,8 +419,7 @@ static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = to_mt9m111(client); + struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); a->c = mt9m111->rect; a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -496,8 +446,7 @@ static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) static int mt9m111_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = to_mt9m111(client); + struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); mf->width = mt9m111->rect.width; mf->height = mt9m111->rect.height; @@ -508,51 +457,73 @@ static int mt9m111_g_fmt(struct v4l2_subdev *sd, return 0; } -static int mt9m111_set_pixfmt(struct i2c_client *client, +static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111, enum v4l2_mbus_pixelcode code) { - struct mt9m111 *mt9m111 = to_mt9m111(client); + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); + u16 data_outfmt2, mask_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER | + MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB | + MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 | + MT9M111_OUTFMT_RGB444x | MT9M111_OUTFMT_RGBx444 | + MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN | + MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B; int ret; switch (code) { case V4L2_MBUS_FMT_SBGGR8_1X8: - ret = mt9m111_setfmt_bayer8(client); + data_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER | + MT9M111_OUTFMT_RGB; break; case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE: - ret = mt9m111_setfmt_bayer10(client); + data_outfmt2 = MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB; break; case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: - ret = mt9m111_setfmt_rgb555(client); + data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555 | + MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN; + break; + case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE: + data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555; break; case V4L2_MBUS_FMT_RGB565_2X8_LE: - ret = mt9m111_setfmt_rgb565(client); + data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 | + MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN; + break; + case V4L2_MBUS_FMT_RGB565_2X8_BE: + data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565; + break; + case V4L2_MBUS_FMT_BGR565_2X8_BE: + data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 | + MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B; + break; + case V4L2_MBUS_FMT_BGR565_2X8_LE: + data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 | + MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN | + MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B; break; case V4L2_MBUS_FMT_UYVY8_2X8: - mt9m111->swap_yuv_y_chromas = 0; - mt9m111->swap_yuv_cb_cr = 0; - ret = mt9m111_setfmt_yuv(client); + data_outfmt2 = 0; break; case V4L2_MBUS_FMT_VYUY8_2X8: - mt9m111->swap_yuv_y_chromas = 0; - mt9m111->swap_yuv_cb_cr = 1; - ret = mt9m111_setfmt_yuv(client); + data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B; break; case V4L2_MBUS_FMT_YUYV8_2X8: - mt9m111->swap_yuv_y_chromas = 1; - mt9m111->swap_yuv_cb_cr = 0; - ret = mt9m111_setfmt_yuv(client); + data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN; break; case V4L2_MBUS_FMT_YVYU8_2X8: - mt9m111->swap_yuv_y_chromas = 1; - mt9m111->swap_yuv_cb_cr = 1; - ret = mt9m111_setfmt_yuv(client); + data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN | + MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B; break; default: - dev_err(&client->dev, "Pixel format not handled : %x\n", - code); - ret = -EINVAL; + dev_err(&client->dev, "Pixel format not handled: %x\n", code); + return -EINVAL; } + ret = reg_mask(OUTPUT_FORMAT_CTRL2_A, data_outfmt2, + mask_outfmt2); + if (!ret) + ret = reg_mask(OUTPUT_FORMAT_CTRL2_B, data_outfmt2, + mask_outfmt2); + return ret; } @@ -561,7 +532,7 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd, { struct i2c_client *client = v4l2_get_subdevdata(sd); const struct mt9m111_datafmt *fmt; - struct mt9m111 *mt9m111 = to_mt9m111(client); + struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); struct v4l2_rect rect = { .left = mt9m111->rect.left, .top = mt9m111->rect.top, @@ -579,9 +550,9 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd, "%s code=%x left=%d, top=%d, width=%d, height=%d\n", __func__, mf->code, rect.left, rect.top, rect.width, rect.height); - ret = mt9m111_make_rect(client, &rect); + ret = mt9m111_make_rect(mt9m111, &rect); if (!ret) - ret = mt9m111_set_pixfmt(client, mf->code); + ret = mt9m111_set_pixfmt(mt9m111, mf->code); if (!ret) { mt9m111->rect = rect; mt9m111->fmt = fmt; @@ -594,8 +565,7 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd, static int mt9m111_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = to_mt9m111(client); + struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); const struct mt9m111_datafmt *fmt; bool bayer = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 || mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE; @@ -635,7 +605,7 @@ static int mt9m111_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = to_mt9m111(client); + struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) return -EINVAL; @@ -726,21 +696,16 @@ static const struct v4l2_queryctrl mt9m111_controls[] = { } }; -static int mt9m111_resume(struct soc_camera_device *icd); -static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state); - static struct soc_camera_ops mt9m111_ops = { - .suspend = mt9m111_suspend, - .resume = mt9m111_resume, .query_bus_param = mt9m111_query_bus_param, .set_bus_param = mt9m111_set_bus_param, .controls = mt9m111_controls, .num_controls = ARRAY_SIZE(mt9m111_controls), }; -static int mt9m111_set_flip(struct i2c_client *client, int flip, int mask) +static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask) { - struct mt9m111 *mt9m111 = to_mt9m111(client); + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); int ret; if (mt9m111->context == HIGHPOWER) { @@ -758,8 +723,9 @@ static int mt9m111_set_flip(struct i2c_client *client, int flip, int mask) return ret; } -static int mt9m111_get_global_gain(struct i2c_client *client) +static int mt9m111_get_global_gain(struct mt9m111 *mt9m111) { + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); int data; data = reg_read(GLOBAL_GAIN); @@ -769,9 +735,9 @@ static int mt9m111_get_global_gain(struct i2c_client *client) return data; } -static int mt9m111_set_global_gain(struct i2c_client *client, int gain) +static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain) { - struct mt9m111 *mt9m111 = to_mt9m111(client); + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); u16 val; if (gain > 63 * 2 * 2) @@ -788,9 +754,9 @@ static int mt9m111_set_global_gain(struct i2c_client *client, int gain) return reg_write(GLOBAL_GAIN, val); } -static int mt9m111_set_autoexposure(struct i2c_client *client, int on) +static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on) { - struct mt9m111 *mt9m111 = to_mt9m111(client); + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); int ret; if (on) @@ -804,9 +770,9 @@ static int mt9m111_set_autoexposure(struct i2c_client *client, int on) return ret; } -static int mt9m111_set_autowhitebalance(struct i2c_client *client, int on) +static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on) { - struct mt9m111 *mt9m111 = to_mt9m111(client); + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); int ret; if (on) @@ -823,7 +789,7 @@ static int mt9m111_set_autowhitebalance(struct i2c_client *client, int on) static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = to_mt9m111(client); + struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); int data; switch (ctrl->id) { @@ -848,7 +814,7 @@ static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS); break; case V4L2_CID_GAIN: - data = mt9m111_get_global_gain(client); + data = mt9m111_get_global_gain(mt9m111); if (data < 0) return data; ctrl->value = data; @@ -865,8 +831,7 @@ static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = to_mt9m111(client); + struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); const struct v4l2_queryctrl *qctrl; int ret; @@ -877,22 +842,22 @@ static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) switch (ctrl->id) { case V4L2_CID_VFLIP: mt9m111->vflip = ctrl->value; - ret = mt9m111_set_flip(client, ctrl->value, + ret = mt9m111_set_flip(mt9m111, ctrl->value, MT9M111_RMB_MIRROR_ROWS); break; case V4L2_CID_HFLIP: mt9m111->hflip = ctrl->value; - ret = mt9m111_set_flip(client, ctrl->value, + ret = mt9m111_set_flip(mt9m111, ctrl->value, MT9M111_RMB_MIRROR_COLS); break; case V4L2_CID_GAIN: - ret = mt9m111_set_global_gain(client, ctrl->value); + ret = mt9m111_set_global_gain(mt9m111, ctrl->value); break; case V4L2_CID_EXPOSURE_AUTO: - ret = mt9m111_set_autoexposure(client, ctrl->value); + ret = mt9m111_set_autoexposure(mt9m111, ctrl->value); break; case V4L2_CID_AUTO_WHITE_BALANCE: - ret = mt9m111_set_autowhitebalance(client, ctrl->value); + ret = mt9m111_set_autowhitebalance(mt9m111, ctrl->value); break; default: ret = -EINVAL; @@ -901,60 +866,52 @@ static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) return ret; } -static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state) +static int mt9m111_suspend(struct mt9m111 *mt9m111) { - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct mt9m111 *mt9m111 = to_mt9m111(client); - - mt9m111->gain = mt9m111_get_global_gain(client); + mt9m111->gain = mt9m111_get_global_gain(mt9m111); return 0; } -static int mt9m111_restore_state(struct i2c_client *client) +static void mt9m111_restore_state(struct mt9m111 *mt9m111) { - struct mt9m111 *mt9m111 = to_mt9m111(client); - - mt9m111_set_context(client, mt9m111->context); - mt9m111_set_pixfmt(client, mt9m111->fmt->code); - mt9m111_setup_rect(client, &mt9m111->rect); - mt9m111_set_flip(client, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); - mt9m111_set_flip(client, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); - mt9m111_set_global_gain(client, mt9m111->gain); - mt9m111_set_autoexposure(client, mt9m111->autoexposure); - mt9m111_set_autowhitebalance(client, mt9m111->autowhitebalance); - return 0; + mt9m111_set_context(mt9m111, mt9m111->context); + mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code); + mt9m111_setup_rect(mt9m111, &mt9m111->rect); + mt9m111_set_flip(mt9m111, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); + mt9m111_set_flip(mt9m111, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); + mt9m111_set_global_gain(mt9m111, mt9m111->gain); + mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure); + mt9m111_set_autowhitebalance(mt9m111, mt9m111->autowhitebalance); } -static int mt9m111_resume(struct soc_camera_device *icd) +static int mt9m111_resume(struct mt9m111 *mt9m111) { - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct mt9m111 *mt9m111 = to_mt9m111(client); int ret = 0; if (mt9m111->powered) { - ret = mt9m111_enable(client); + ret = mt9m111_enable(mt9m111); if (!ret) - ret = mt9m111_reset(client); + ret = mt9m111_reset(mt9m111); if (!ret) - ret = mt9m111_restore_state(client); + mt9m111_restore_state(mt9m111); } return ret; } -static int mt9m111_init(struct i2c_client *client) +static int mt9m111_init(struct mt9m111 *mt9m111) { - struct mt9m111 *mt9m111 = to_mt9m111(client); + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); int ret; mt9m111->context = HIGHPOWER; - ret = mt9m111_enable(client); + ret = mt9m111_enable(mt9m111); if (!ret) - ret = mt9m111_reset(client); + ret = mt9m111_reset(mt9m111); if (!ret) - ret = mt9m111_set_context(client, mt9m111->context); + ret = mt9m111_set_context(mt9m111, mt9m111->context); if (!ret) - ret = mt9m111_set_autoexposure(client, mt9m111->autoexposure); + ret = mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure); if (ret) dev_err(&client->dev, "mt9m111 init failed: %d\n", ret); return ret; @@ -971,20 +928,13 @@ static int mt9m111_video_probe(struct soc_camera_device *icd, s32 data; int ret; - /* - * We must have a parent by now. And it cannot be a wrong one. - * So this entire test is completely redundant. - */ - if (!icd->dev.parent || - to_soc_camera_host(icd->dev.parent)->nr != icd->iface) - return -ENODEV; + /* We must have a parent by now. And it cannot be a wrong one. */ + BUG_ON(!icd->parent || + to_soc_camera_host(icd->parent)->nr != icd->iface); mt9m111->autoexposure = 1; mt9m111->autowhitebalance = 1; - mt9m111->swap_rgb_even_odd = 1; - mt9m111->swap_rgb_red_blue = 1; - data = reg_read(CHIP_VERSION); switch (data) { @@ -1005,16 +955,51 @@ static int mt9m111_video_probe(struct soc_camera_device *icd, goto ei2c; } - ret = mt9m111_init(client); + ret = mt9m111_init(mt9m111); ei2c: return ret; } +static int mt9m111_s_power(struct v4l2_subdev *sd, int on) +{ + struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + mutex_lock(&mt9m111->power_lock); + + /* + * If the power count is modified from 0 to != 0 or from != 0 to 0, + * update the power state. + */ + if (mt9m111->power_count == !on) { + if (on) { + ret = mt9m111_resume(mt9m111); + if (ret) { + dev_err(&client->dev, + "Failed to resume the sensor: %d\n", ret); + goto out; + } + } else { + mt9m111_suspend(mt9m111); + } + } + + /* Update the power count. */ + mt9m111->power_count += on ? 1 : -1; + WARN_ON(mt9m111->power_count < 0); + +out: + mutex_unlock(&mt9m111->power_lock); + return ret; +} + static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { .g_ctrl = mt9m111_g_ctrl, .s_ctrl = mt9m111_s_ctrl, .g_chip_ident = mt9m111_g_chip_ident, + .s_power = mt9m111_s_power, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = mt9m111_g_register, .s_register = mt9m111_s_register, diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 7ce279c3751dbd2dd5379c454046473d7b0b775e..30547cc3f89b374e286ddf9da1105bf9317db2df 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -700,8 +700,7 @@ static int mt9t031_runtime_suspend(struct device *dev) static int mt9t031_runtime_resume(struct device *dev) { struct video_device *vdev = to_video_device(dev); - struct soc_camera_device *icd = container_of(vdev->parent, - struct soc_camera_device, dev); + struct soc_camera_device *icd = dev_get_drvdata(vdev->parent); struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t031 *mt9t031 = to_mt9t031(client); diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index bffa9ee10968e315172b1cc4678d3c2e1c0397b5..d2e0a50063a269e54987f7d3e9e5221855786c2e 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c @@ -1057,13 +1057,9 @@ static int mt9t112_camera_probe(struct soc_camera_device *icd, const char *devname; int chipid; - /* - * We must have a parent by now. And it cannot be a wrong one. - * So this entire test is completely redundant. - */ - if (!icd->dev.parent || - to_soc_camera_host(icd->dev.parent)->nr != icd->iface) - return -ENODEV; + /* We must have a parent by now. And it cannot be a wrong one. */ + BUG_ON(!icd->parent || + to_soc_camera_host(icd->parent)->nr != icd->iface); /* * check and show chip ID diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c index 4904d25f689fdf61c60fc0d8db2d40f80fd473f8..893a8b8f514134a4aa68645e8029166e75e16c02 100644 --- a/drivers/media/video/mt9v011.c +++ b/drivers/media/video/mt9v011.c @@ -54,10 +54,19 @@ static struct v4l2_queryctrl mt9v011_qctrl[] = { .type = V4L2_CTRL_TYPE_INTEGER, .name = "Gain", .minimum = 0, - .maximum = (1 << 10) - 1, + .maximum = (1 << 12) - 1 - 0x0020, .step = 1, .default_value = 0x0020, .flags = 0, + }, { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 2047, + .step = 1, + .default_value = 0x01fc, + .flags = 0, }, { .id = V4L2_CID_RED_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, @@ -105,7 +114,8 @@ struct mt9v011 { unsigned hflip:1; unsigned vflip:1; - u16 global_gain, red_bal, blue_bal; + u16 global_gain, exposure; + s16 red_bal, blue_bal; }; static inline struct mt9v011 *to_mt9v011(struct v4l2_subdev *sd) @@ -180,24 +190,68 @@ static const struct i2c_reg_value mt9v011_init_default[] = { { R07_MT9V011_OUT_CTRL, 0x0002 }, /* chip enable */ }; + +static u16 calc_mt9v011_gain(s16 lineargain) +{ + + u16 digitalgain = 0; + u16 analogmult = 0; + u16 analoginit = 0; + + if (lineargain < 0) + lineargain = 0; + + /* recommended minimum */ + lineargain += 0x0020; + + if (lineargain > 2047) + lineargain = 2047; + + if (lineargain > 1023) { + digitalgain = 3; + analogmult = 3; + analoginit = lineargain / 16; + } else if (lineargain > 511) { + digitalgain = 1; + analogmult = 3; + analoginit = lineargain / 8; + } else if (lineargain > 255) { + analogmult = 3; + analoginit = lineargain / 4; + } else if (lineargain > 127) { + analogmult = 1; + analoginit = lineargain / 2; + } else + analoginit = lineargain; + + return analoginit + (analogmult << 7) + (digitalgain << 9); + +} + static void set_balance(struct v4l2_subdev *sd) { struct mt9v011 *core = to_mt9v011(sd); - u16 green1_gain, green2_gain, blue_gain, red_gain; + u16 green_gain, blue_gain, red_gain; + u16 exposure; + s16 bal; - green1_gain = core->global_gain; - green2_gain = core->global_gain; + exposure = core->exposure; - blue_gain = core->global_gain + - core->global_gain * core->blue_bal / (1 << 9); + green_gain = calc_mt9v011_gain(core->global_gain); - red_gain = core->global_gain + - core->global_gain * core->blue_bal / (1 << 9); + bal = core->global_gain; + bal += (core->blue_bal * core->global_gain / (1 << 7)); + blue_gain = calc_mt9v011_gain(bal); - mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green1_gain); - mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN, green1_gain); + bal = core->global_gain; + bal += (core->red_bal * core->global_gain / (1 << 7)); + red_gain = calc_mt9v011_gain(bal); + + mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green_gain); + mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN, green_gain); mt9v011_write(sd, R2C_MT9V011_BLUE_GAIN, blue_gain); mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain); + mt9v011_write(sd, R09_MT9V011_SHUTTER_WIDTH, exposure); } static void calc_fps(struct v4l2_subdev *sd, u32 *numerator, u32 *denominator) @@ -286,7 +340,7 @@ static void set_res(struct v4l2_subdev *sd) * be missing. */ - hstart = 14 + (640 - core->width) / 2; + hstart = 20 + (640 - core->width) / 2; mt9v011_write(sd, R02_MT9V011_COLSTART, hstart); mt9v011_write(sd, R04_MT9V011_WIDTH, core->width); mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width); @@ -338,6 +392,9 @@ static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) case V4L2_CID_GAIN: ctrl->value = core->global_gain; return 0; + case V4L2_CID_EXPOSURE: + ctrl->value = core->exposure; + return 0; case V4L2_CID_RED_BALANCE: ctrl->value = core->red_bal; return 0; @@ -392,6 +449,9 @@ static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) case V4L2_CID_GAIN: core->global_gain = ctrl->value; break; + case V4L2_CID_EXPOSURE: + core->exposure = ctrl->value; + break; case V4L2_CID_RED_BALANCE: core->red_bal = ctrl->value; break; @@ -598,6 +658,7 @@ static int mt9v011_probe(struct i2c_client *c, } core->global_gain = 0x0024; + core->exposure = 0x01fc; core->width = 640; core->height = 480; core->xtal = 27000000; /* Hz */ diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index fc76ed1c08e59a43baf0a3632d0417734b807d7a..51b0fccbfe70f922080f25bf15122816466ff26a 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -728,9 +728,9 @@ static int mt9v022_video_probe(struct soc_camera_device *icd, int ret; unsigned long flags; - if (!icd->dev.parent || - to_soc_camera_host(icd->dev.parent)->nr != icd->iface) - return -ENODEV; + /* We must have a parent by now. And it cannot be a wrong one. */ + BUG_ON(!icd->parent || + to_soc_camera_host(icd->parent)->nr != icd->iface); /* Read out the chip version register */ data = reg_read(client, MT9V022_CHIP_VERSION); @@ -809,8 +809,8 @@ static void mt9v022_video_remove(struct soc_camera_device *icd) { struct soc_camera_link *icl = to_soc_camera_link(icd); - dev_dbg(&icd->dev, "Video removed: %p, %p\n", - icd->dev.parent, icd->vdev); + dev_dbg(icd->pdev, "Video removed: %p, %p\n", + icd->parent, icd->vdev); if (icl->free_bus) icl->free_bus(icl); } diff --git a/drivers/media/video/mt9v032.c b/drivers/media/video/mt9v032.c index 1319c2c48aff7ee3e0c56bc20aec69bc32a6a438..c64e1dc4cb4e52585f3518564cf334d2b2bf55ba 100644 --- a/drivers/media/video/mt9v032.c +++ b/drivers/media/video/mt9v032.c @@ -31,14 +31,14 @@ #define MT9V032_CHIP_VERSION 0x00 #define MT9V032_CHIP_ID_REV1 0x1311 #define MT9V032_CHIP_ID_REV3 0x1313 -#define MT9V032_ROW_START 0x01 -#define MT9V032_ROW_START_MIN 4 -#define MT9V032_ROW_START_DEF 10 -#define MT9V032_ROW_START_MAX 482 -#define MT9V032_COLUMN_START 0x02 +#define MT9V032_COLUMN_START 0x01 #define MT9V032_COLUMN_START_MIN 1 -#define MT9V032_COLUMN_START_DEF 2 +#define MT9V032_COLUMN_START_DEF 1 #define MT9V032_COLUMN_START_MAX 752 +#define MT9V032_ROW_START 0x02 +#define MT9V032_ROW_START_MIN 4 +#define MT9V032_ROW_START_DEF 5 +#define MT9V032_ROW_START_MAX 482 #define MT9V032_WINDOW_HEIGHT 0x03 #define MT9V032_WINDOW_HEIGHT_MIN 1 #define MT9V032_WINDOW_HEIGHT_DEF 480 @@ -420,13 +420,13 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev, struct v4l2_rect *__crop; struct v4l2_rect rect; - /* Clamp the crop rectangle boundaries and align them to a multiple of 2 - * pixels. + /* Clamp the crop rectangle boundaries and align them to a non multiple + * of 2 pixels to ensure a GRBG Bayer pattern. */ - rect.left = clamp(ALIGN(crop->rect.left, 2), + rect.left = clamp(ALIGN(crop->rect.left + 1, 2) - 1, MT9V032_COLUMN_START_MIN, MT9V032_COLUMN_START_MAX); - rect.top = clamp(ALIGN(crop->rect.top, 2), + rect.top = clamp(ALIGN(crop->rect.top + 1, 2) - 1, MT9V032_ROW_START_MIN, MT9V032_ROW_START_MAX); rect.width = clamp(ALIGN(crop->rect.width, 2), diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c index 63f8a0cc33d89ec167701c1bee1a0614eebed89f..087db12a3a678eed5ef67f2b273746828da10d91 100644 --- a/drivers/media/video/mx1_camera.c +++ b/drivers/media/video/mx1_camera.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include @@ -73,7 +72,7 @@ #define CSISR_SOF_INT (1 << 16) #define CSISR_DRDY (1 << 0) -#define VERSION_CODE KERNEL_VERSION(0, 0, 1) +#define DRIVER_VERSION "0.0.2" #define DRIVER_NAME "mx1-camera" #define CSI_IRQ_MASK (CSISR_SFF_OR_INT | CSISR_RFF_OR_INT | \ @@ -142,7 +141,7 @@ static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size; - dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size); + dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size); return 0; } @@ -154,7 +153,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf) BUG_ON(in_interrupt()); - dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); /* @@ -179,7 +178,7 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq, if (bytes_per_line < 0) return bytes_per_line; - dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); /* Added list head initialization on alloc */ @@ -232,7 +231,7 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq, static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev) { struct videobuf_buffer *vbuf = &pcdev->active->vb; - struct device *dev = pcdev->icd->dev.parent; + struct device *dev = pcdev->icd->parent; int ret; if (unlikely(!pcdev->active)) { @@ -256,11 +255,11 @@ static void mx1_videobuf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { struct soc_camera_device *icd = vq->priv_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx1_camera_dev *pcdev = ici->priv; struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); - dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); list_add_tail(&vb->queue, &pcdev->capture); @@ -287,7 +286,7 @@ static void mx1_videobuf_release(struct videobuf_queue *vq, struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); #ifdef DEBUG struct soc_camera_device *icd = vq->priv_data; - struct device *dev = icd->dev.parent; + struct device *dev = icd->parent; dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); @@ -343,7 +342,7 @@ static void mx1_camera_wakeup(struct mx1_camera_dev *pcdev, static void mx1_camera_dma_irq(int channel, void *data) { struct mx1_camera_dev *pcdev = data; - struct device *dev = pcdev->icd->dev.parent; + struct device *dev = pcdev->icd->parent; struct mx1_buffer *buf; struct videobuf_buffer *vb; unsigned long flags; @@ -378,10 +377,10 @@ static struct videobuf_queue_ops mx1_videobuf_ops = { static void mx1_camera_init_videobuf(struct videobuf_queue *q, struct soc_camera_device *icd) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx1_camera_dev *pcdev = ici->priv; - videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->dev.parent, + videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->parent, &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, sizeof(struct mx1_buffer), icd, &icd->video_lock); @@ -401,7 +400,7 @@ static int mclk_get_divisor(struct mx1_camera_dev *pcdev) */ div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1; - dev_dbg(pcdev->icd->dev.parent, + dev_dbg(pcdev->icd->parent, "System clock %lukHz, target freq %dkHz, divisor %lu\n", lcdclk / 1000, mclk / 1000, div); @@ -412,7 +411,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev) { unsigned int csicr1 = CSICR1_EN; - dev_dbg(pcdev->icd->dev.parent, "Activate device\n"); + dev_dbg(pcdev->icd->parent, "Activate device\n"); clk_enable(pcdev->clk); @@ -428,7 +427,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev) static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev) { - dev_dbg(pcdev->icd->dev.parent, "Deactivate device\n"); + dev_dbg(pcdev->icd->parent, "Deactivate device\n"); /* Disable all CSI interface */ __raw_writel(0x00, pcdev->base + CSICR1); @@ -442,13 +441,13 @@ static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev) */ static int mx1_camera_add_device(struct soc_camera_device *icd) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx1_camera_dev *pcdev = ici->priv; if (pcdev->icd) return -EBUSY; - dev_info(icd->dev.parent, "MX1 Camera driver attached to camera %d\n", + dev_info(icd->parent, "MX1 Camera driver attached to camera %d\n", icd->devnum); mx1_camera_activate(pcdev); @@ -460,7 +459,7 @@ static int mx1_camera_add_device(struct soc_camera_device *icd) static void mx1_camera_remove_device(struct soc_camera_device *icd) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx1_camera_dev *pcdev = ici->priv; unsigned int csicr1; @@ -473,7 +472,7 @@ static void mx1_camera_remove_device(struct soc_camera_device *icd) /* Stop DMA engine */ imx_dma_disable(pcdev->dma_chan); - dev_info(icd->dev.parent, "MX1 Camera driver detached from camera %d\n", + dev_info(icd->parent, "MX1 Camera driver detached from camera %d\n", icd->devnum); mx1_camera_deactivate(pcdev); @@ -491,7 +490,7 @@ static int mx1_camera_set_crop(struct soc_camera_device *icd, static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx1_camera_dev *pcdev = ici->priv; unsigned long camera_flags, common_flags; unsigned int csicr1; @@ -562,14 +561,14 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); if (!xlate) { - dev_warn(icd->dev.parent, "Format %x not found\n", + dev_warn(icd->parent, "Format %x not found\n", pix->pixelformat); return -EINVAL; } buswidth = xlate->host_fmt->bits_per_sample; if (buswidth > 8) { - dev_warn(icd->dev.parent, + dev_warn(icd->parent, "bits-per-sample %d for format %x unsupported\n", buswidth, pix->pixelformat); return -EINVAL; @@ -609,7 +608,7 @@ static int mx1_camera_try_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); if (!xlate) { - dev_warn(icd->dev.parent, "Format %x not found\n", + dev_warn(icd->parent, "Format %x not found\n", pix->pixelformat); return -EINVAL; } @@ -676,7 +675,6 @@ static int mx1_camera_querycap(struct soc_camera_host *ici, { /* cap->name is set by the friendly caller:-> */ strlcpy(cap->card, "i.MX1/i.MXL Camera", sizeof(cap->card)); - cap->version = VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; return 0; @@ -883,4 +881,5 @@ module_exit(mx1_camera_exit); MODULE_DESCRIPTION("i.MX1/i.MXL SoC Camera Host driver"); MODULE_AUTHOR("Paulius Zaleckas "); MODULE_LICENSE("GPL v2"); +MODULE_VERSION(DRIVER_VERSION); MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c index 4eab1c620318ef49c22aed6e2a208646b27f513c..ec2410c0c8069cddda1d19986d2235072bccbfbd 100644 --- a/drivers/media/video/mx2_camera.c +++ b/drivers/media/video/mx2_camera.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -47,7 +46,7 @@ #include #define MX2_CAM_DRV_NAME "mx2-camera" -#define MX2_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5) +#define MX2_CAM_VERSION "0.0.6" #define MX2_CAM_DRIVER_DESCRIPTION "i.MX2x_Camera" /* reset values */ @@ -278,7 +277,7 @@ static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) */ static int mx2_camera_add_device(struct soc_camera_device *icd) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx2_camera_dev *pcdev = ici->priv; int ret; u32 csicr1; @@ -303,7 +302,7 @@ static int mx2_camera_add_device(struct soc_camera_device *icd) pcdev->icd = icd; - dev_info(icd->dev.parent, "Camera driver attached to camera %d\n", + dev_info(icd->parent, "Camera driver attached to camera %d\n", icd->devnum); return 0; @@ -311,12 +310,12 @@ static int mx2_camera_add_device(struct soc_camera_device *icd) static void mx2_camera_remove_device(struct soc_camera_device *icd) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx2_camera_dev *pcdev = ici->priv; BUG_ON(icd != pcdev->icd); - dev_info(icd->dev.parent, "Camera driver detached from camera %d\n", + dev_info(icd->parent, "Camera driver detached from camera %d\n", icd->devnum); mx2_camera_deactivate(pcdev); @@ -437,7 +436,7 @@ static int mx2_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); - dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); + dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size); if (bytes_per_line < 0) return bytes_per_line; @@ -457,7 +456,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf) struct soc_camera_device *icd = vq->priv_data; struct videobuf_buffer *vb = &buf->vb; - dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); /* @@ -467,7 +466,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf) videobuf_waiton(vq, vb, 0, 0); videobuf_dma_contig_free(vq, vb); - dev_dbg(&icd->dev, "%s freed\n", __func__); + dev_dbg(icd->parent, "%s freed\n", __func__); vb->state = VIDEOBUF_NEEDS_INIT; } @@ -481,7 +480,7 @@ static int mx2_videobuf_prepare(struct videobuf_queue *vq, icd->current_fmt->host_fmt); int ret = 0; - dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); if (bytes_per_line < 0) @@ -533,12 +532,12 @@ static void mx2_videobuf_queue(struct videobuf_queue *vq, { struct soc_camera_device *icd = vq->priv_data; struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + to_soc_camera_host(icd->parent); struct mx2_camera_dev *pcdev = ici->priv; struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); unsigned long flags; - dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); spin_lock_irqsave(&pcdev->lock, flags); @@ -611,27 +610,27 @@ static void mx2_videobuf_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) { struct soc_camera_device *icd = vq->priv_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx2_camera_dev *pcdev = ici->priv; struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); unsigned long flags; #ifdef DEBUG - dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); switch (vb->state) { case VIDEOBUF_ACTIVE: - dev_info(&icd->dev, "%s (active)\n", __func__); + dev_info(icd->parent, "%s (active)\n", __func__); break; case VIDEOBUF_QUEUED: - dev_info(&icd->dev, "%s (queued)\n", __func__); + dev_info(icd->parent, "%s (queued)\n", __func__); break; case VIDEOBUF_PREPARED: - dev_info(&icd->dev, "%s (prepared)\n", __func__); + dev_info(icd->parent, "%s (prepared)\n", __func__); break; default: - dev_info(&icd->dev, "%s (unknown) %d\n", __func__, + dev_info(icd->parent, "%s (unknown) %d\n", __func__, vb->state); break; } @@ -678,7 +677,7 @@ static struct videobuf_queue_ops mx2_videobuf_ops = { static void mx2_camera_init_videobuf(struct videobuf_queue *q, struct soc_camera_device *icd) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx2_camera_dev *pcdev = ici->priv; videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev, @@ -719,7 +718,7 @@ static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, int bytesperline) { struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + to_soc_camera_host(icd->parent); struct mx2_camera_dev *pcdev = ici->priv; writel(pcdev->discard_buffer_dma, @@ -772,7 +771,7 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) { struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + to_soc_camera_host(icd->parent); struct mx2_camera_dev *pcdev = ici->priv; unsigned long camera_flags, common_flags; int ret = 0; @@ -891,7 +890,7 @@ static int mx2_camera_set_crop(struct soc_camera_device *icd, if (ret < 0) return ret; - dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n", + dev_dbg(icd->parent, "Sensor cropped %dx%d\n", mf.width, mf.height); icd->user_width = mf.width; @@ -911,7 +910,7 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); if (!xlate) { - dev_warn(icd->dev.parent, "Format %x not found\n", + dev_warn(icd->parent, "Format %x not found\n", pix->pixelformat); return -EINVAL; } @@ -951,7 +950,7 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (pixfmt && !xlate) { - dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt); + dev_warn(icd->parent, "Format %x not found\n", pixfmt); return -EINVAL; } @@ -974,11 +973,16 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, if (pix->bytesperline < 0) return pix->bytesperline; pix->sizeimage = pix->height * pix->bytesperline; - if (pix->sizeimage > (4 * 0x3ffff)) { /* CSIRXCNT limit */ - dev_warn(icd->dev.parent, - "Image size (%u) above limit\n", - pix->sizeimage); - return -EINVAL; + /* Check against the CSIRXCNT limit */ + if (pix->sizeimage > 4 * 0x3ffff) { + /* Adjust geometry, preserve aspect ratio */ + unsigned int new_height = int_sqrt(4 * 0x3ffff * + pix->height / pix->bytesperline); + pix->width = new_height * pix->width / pix->height; + pix->height = new_height; + pix->bytesperline = soc_mbus_bytes_per_line(pix->width, + xlate->host_fmt); + BUG_ON(pix->bytesperline < 0); } } @@ -996,7 +1000,7 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, if (mf.field == V4L2_FIELD_ANY) mf.field = V4L2_FIELD_NONE; if (mf.field != V4L2_FIELD_NONE) { - dev_err(icd->dev.parent, "Field type %d unsupported.\n", + dev_err(icd->parent, "Field type %d unsupported.\n", mf.field); return -EINVAL; } @@ -1014,7 +1018,6 @@ static int mx2_camera_querycap(struct soc_camera_host *ici, { /* cap->name is set by the friendly caller:-> */ strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card)); - cap->version = MX2_CAM_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; return 0; @@ -1523,3 +1526,4 @@ module_exit(mx2_camera_exit); MODULE_DESCRIPTION("i.MX27/i.MX25 SoC Camera Host driver"); MODULE_AUTHOR("Sascha Hauer "); MODULE_LICENSE("GPL"); +MODULE_VERSION(MX2_CAM_VERSION); diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index c7680eb83664ea6606d238cd6a53d55380194912..c045b47803adfdca07328815b08c34ab009ea9e3 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -11,7 +11,6 @@ #include #include -#include #include #include #include @@ -195,7 +194,7 @@ static int mx3_videobuf_setup(struct vb2_queue *vq, unsigned long sizes[], void *alloc_ctxs[]) { struct soc_camera_device *icd = soc_camera_from_vb2q(vq); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); @@ -224,7 +223,7 @@ static int mx3_videobuf_setup(struct vb2_queue *vq, static int mx3_videobuf_prepare(struct vb2_buffer *vb) { struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; struct scatterlist *sg; @@ -242,7 +241,7 @@ static int mx3_videobuf_prepare(struct vb2_buffer *vb) new_size = bytes_per_line * icd->user_height; if (vb2_plane_size(vb, 0) < new_size) { - dev_err(icd->dev.parent, "Buffer too small (%lu < %zu)\n", + dev_err(icd->parent, "Buffer too small (%lu < %zu)\n", vb2_plane_size(vb, 0), new_size); return -ENOBUFS; } @@ -284,7 +283,7 @@ static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc) static void mx3_videobuf_queue(struct vb2_buffer *vb) { struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct mx3_camera_buffer *buf = to_mx3_vb(vb); struct dma_async_tx_descriptor *txd = buf->txd; @@ -337,7 +336,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb) spin_unlock_irq(&mx3_cam->lock); cookie = txd->tx_submit(txd); - dev_dbg(icd->dev.parent, "Submitted cookie %d DMA 0x%08x\n", + dev_dbg(icd->parent, "Submitted cookie %d DMA 0x%08x\n", cookie, sg_dma_address(&buf->sg)); if (cookie >= 0) @@ -358,13 +357,13 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb) static void mx3_videobuf_release(struct vb2_buffer *vb) { struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct mx3_camera_buffer *buf = to_mx3_vb(vb); struct dma_async_tx_descriptor *txd = buf->txd; unsigned long flags; - dev_dbg(icd->dev.parent, + dev_dbg(icd->parent, "Release%s DMA 0x%08x, queue %sempty\n", mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg), list_empty(&buf->queue) ? "" : "not "); @@ -403,7 +402,7 @@ static int mx3_videobuf_init(struct vb2_buffer *vb) static int mx3_stop_streaming(struct vb2_queue *q) { struct soc_camera_device *icd = soc_camera_from_vb2q(q); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; struct dma_chan *chan; @@ -499,7 +498,7 @@ static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam, clk_enable(mx3_cam->clk); rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk); - dev_dbg(icd->dev.parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate); + dev_dbg(icd->parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate); if (rate) clk_set_rate(mx3_cam->clk, rate); } @@ -507,7 +506,7 @@ static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam, /* Called with .video_lock held */ static int mx3_camera_add_device(struct soc_camera_device *icd) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; if (mx3_cam->icd) @@ -517,7 +516,7 @@ static int mx3_camera_add_device(struct soc_camera_device *icd) mx3_cam->icd = icd; - dev_info(icd->dev.parent, "MX3 Camera driver attached to camera %d\n", + dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n", icd->devnum); return 0; @@ -526,7 +525,7 @@ static int mx3_camera_add_device(struct soc_camera_device *icd) /* Called with .video_lock held */ static void mx3_camera_remove_device(struct soc_camera_device *icd) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; @@ -541,7 +540,7 @@ static void mx3_camera_remove_device(struct soc_camera_device *icd) mx3_cam->icd = NULL; - dev_info(icd->dev.parent, "MX3 Camera driver detached from camera %d\n", + dev_info(icd->parent, "MX3 Camera driver detached from camera %d\n", icd->devnum); } @@ -608,12 +607,12 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam, static int mx3_camera_try_bus_param(struct soc_camera_device *icd, const unsigned int depth) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; unsigned long bus_flags, camera_flags; int ret = test_platform_param(mx3_cam, depth, &bus_flags); - dev_dbg(icd->dev.parent, "request bus width %d bit: %d\n", depth, ret); + dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret); if (ret < 0) return ret; @@ -622,7 +621,7 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd, ret = soc_camera_bus_param_compatible(camera_flags, bus_flags); if (ret < 0) - dev_warn(icd->dev.parent, + dev_warn(icd->parent, "Flags incompatible: camera %lx, host %lx\n", camera_flags, bus_flags); @@ -676,7 +675,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id struct soc_camera_format_xlate *xlate) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct device *dev = icd->dev.parent; + struct device *dev = icd->parent; int formats = 0, ret; enum v4l2_mbus_pixelcode code; const struct soc_mbus_pixelfmt *fmt; @@ -688,7 +687,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id fmt = soc_mbus_get_fmtdesc(code); if (!fmt) { - dev_warn(icd->dev.parent, + dev_warn(icd->parent, "Unsupported format code #%u: %d\n", idx, code); return 0; } @@ -816,7 +815,7 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, struct v4l2_crop *a) { struct v4l2_rect *rect = &a->c; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct v4l2_mbus_framefmt mf; @@ -849,7 +848,7 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, configure_geometry(mx3_cam, mf.width, mf.height, icd->current_fmt->host_fmt); - dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n", + dev_dbg(icd->parent, "Sensor cropped %dx%d\n", mf.width, mf.height); icd->user_width = mf.width; @@ -861,7 +860,7 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, static int mx3_camera_set_fmt(struct soc_camera_device *icd, struct v4l2_format *f) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; @@ -871,13 +870,13 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); if (!xlate) { - dev_warn(icd->dev.parent, "Format %x not found\n", + dev_warn(icd->parent, "Format %x not found\n", pix->pixelformat); return -EINVAL; } stride_align(&pix->width); - dev_dbg(icd->dev.parent, "Set format %dx%d\n", pix->width, pix->height); + dev_dbg(icd->parent, "Set format %dx%d\n", pix->width, pix->height); /* * Might have to perform a complete interface initialisation like in @@ -913,13 +912,7 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, pix->colorspace = mf.colorspace; icd->current_fmt = xlate; - pix->bytesperline = soc_mbus_bytes_per_line(pix->width, - xlate->host_fmt); - if (pix->bytesperline < 0) - return pix->bytesperline; - pix->sizeimage = pix->height * pix->bytesperline; - - dev_dbg(icd->dev.parent, "Sensor set %dx%d\n", pix->width, pix->height); + dev_dbg(icd->parent, "Sensor set %dx%d\n", pix->width, pix->height); return ret; } @@ -936,7 +929,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (pixfmt && !xlate) { - dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt); + dev_warn(icd->parent, "Format %x not found\n", pixfmt); return -EINVAL; } @@ -946,12 +939,6 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, if (pix->width > 4096) pix->width = 4096; - pix->bytesperline = soc_mbus_bytes_per_line(pix->width, - xlate->host_fmt); - if (pix->bytesperline < 0) - return pix->bytesperline; - pix->sizeimage = pix->height * pix->bytesperline; - /* limit to sensor capabilities */ mf.width = pix->width; mf.height = pix->height; @@ -974,7 +961,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, case V4L2_FIELD_NONE: break; default: - dev_err(icd->dev.parent, "Field type %d unsupported.\n", + dev_err(icd->parent, "Field type %d unsupported.\n", mf.field); ret = -EINVAL; } @@ -1000,7 +987,6 @@ static int mx3_camera_querycap(struct soc_camera_host *ici, { /* cap->name is set by the firendly caller:-> */ strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card)); - cap->version = KERNEL_VERSION(0, 2, 2); cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; return 0; @@ -1008,7 +994,7 @@ static int mx3_camera_querycap(struct soc_camera_host *ici, static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; unsigned long bus_flags, camera_flags, common_flags; u32 dw, sens_conf; @@ -1016,7 +1002,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) int buswidth; int ret; const struct soc_camera_format_xlate *xlate; - struct device *dev = icd->dev.parent; + struct device *dev = icd->parent; fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code); if (!fmt) @@ -1325,4 +1311,5 @@ module_exit(mx3_camera_exit); MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver"); MODULE_AUTHOR("Guennadi Liakhovetski "); MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.2.3"); MODULE_ALIAS("platform:" MX3_CAM_DRV_NAME); diff --git a/drivers/media/video/omap/Kconfig b/drivers/media/video/omap/Kconfig index e63233fd2aaab3a4a1cc99e7c0e546cd72a3592c..390ab094f9f2389a0d80deb893f6d357199221fd 100644 --- a/drivers/media/video/omap/Kconfig +++ b/drivers/media/video/omap/Kconfig @@ -1,11 +1,14 @@ +config VIDEO_OMAP2_VOUT_VRFB + bool + config VIDEO_OMAP2_VOUT tristate "OMAP2/OMAP3 V4L2-Display driver" depends on ARCH_OMAP2 || ARCH_OMAP3 select VIDEOBUF_GEN select VIDEOBUF_DMA_CONTIG select OMAP2_DSS - select OMAP2_VRAM - select OMAP2_VRFB + select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 + select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB default n ---help--- V4L2 Display driver support for OMAP2/3 based boards. diff --git a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile index b28788070ae123ce6d59338055e1462040a22658..fc410b438f7d6545b2d35ce19e9fb0cdf43e2333 100644 --- a/drivers/media/video/omap/Makefile +++ b/drivers/media/video/omap/Makefile @@ -4,4 +4,5 @@ # OMAP2/3 Display driver omap-vout-y := omap_vout.o omap_voutlib.o +omap-vout-$(CONFIG_VIDEO_OMAP2_VOUT_VRFB) += omap_vout_vrfb.o obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout.o diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index a647894d3a717a9307be0a0b1ad243012f7d25bf..b5ef36222440bab59f14d8978b099b0cbe0ca8d5 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -35,28 +35,26 @@ #include #include #include -#include #include #include -#include +#include #include #include #include #include -#include #include #include