Digital TV (DVB) devices
------------------------
+Digital TV devices are implemented by several different drivers:
+
+- A bridge driver that is responsible to talk with the bus where the other
+ devices are connected (PCI, USB, SPI), bind to the other drivers and
+ implement the digital demux logic (either in software or in hardware);
+
+- Frontend drivers that are usually implemented as two separate drivers:
+
+ - A tuner driver that implements the logic with commands the part of the
+ hardware with is reponsible to tune into a digital TV transponder or
+ physical channel. The output of a tuner is usually a baseband or
+ Intermediate Frequency (IF) signal;
+
+ - A demodulator driver (a.k.a "demod") that implements the logic with
+ commands the digital TV decoding hardware. The output of a demod is
+ a digital stream, with multiple audio, video and data channels typically
+ multiplexed using MPEG Transport Stream [#f1]_.
+
+On most hardware, the frontend drivers talk with the bridge driver using an
+I2C bus.
+
+.. [#f1] Some standards use TCP/IP for multiplexing data, like DVB-H (an
+ abandoned standard, not used anymore) and ATSC version 3.0 current
+ proposals. Currently, the DVB subsystem doesn't implement those standards.
+
Digital TV Common functions
---------------------------
The Digital TV Frontend kABI defines a driver-internal interface for
registering low-level, hardware specific driver to a hardware independent
frontend layer. It is only of interest for Digital TV device driver writers.
-The header file for this API is named dvb_frontend.h and located in
-drivers/media/dvb-core.
+The header file for this API is named ``dvb_frontend.h`` and located in
+``drivers/media/dvb-core``.
+
+Demodulator driver
+^^^^^^^^^^^^^^^^^^
+
+The demodulator driver is responsible to talk with the decoding part of the
+hardware. Such driver should implement :c:type:`dvb_frontend_ops`, with
+tells what type of digital TV standards are supported, and points to a
+series of functions that allow the DVB core to command the hardware via
+the code under ``drivers/media/dvb-core/dvb_frontend.c``.
+
+A typical example of such struct in a driver ``foo`` is::
+
+ static struct dvb_frontend_ops foo_ops = {
+ .delsys = { SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A },
+ .info = {
+ .name = "foo DVB-T/T2/C driver",
+ .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_QPSK |
+ FE_CAN_QAM_16 |
+ FE_CAN_QAM_32 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 |
+ FE_CAN_QAM_256 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO |
+ FE_CAN_MUTE_TS |
+ FE_CAN_2G_MODULATION,
+ .frequency_min = 42000000, /* Hz */
+ .frequency_max = 1002000000, /* Hz */
+ .symbol_rate_min = 870000,
+ .symbol_rate_max = 11700000
+ },
+ .init = foo_init,
+ .sleep = foo_sleep,
+ .release = foo_release,
+ .set_frontend = foo_set_frontend,
+ .get_frontend = foo_get_frontend,
+ .read_status = foo_get_status_and_stats,
+ .tune = foo_tune,
+ .i2c_gate_ctrl = foo_i2c_gate_ctrl,
+ .get_frontend_algo = foo_get_algo,
+ };
+
+A typical example of such struct in a driver ``bar`` meant to be used on
+Satellite TV reception is::
+
+ static const struct dvb_frontend_ops bar_ops = {
+ .delsys = { SYS_DVBS, SYS_DVBS2 },
+ .info = {
+ .name = "Bar DVB-S/S2 demodulator",
+ .frequency_min = 500000, /* KHz */
+ .frequency_max = 2500000, /* KHz */
+ .frequency_stepsize = 0,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .symbol_rate_tolerance = 500,
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK,
+ },
+ .init = bar_init,
+ .sleep = bar_sleep,
+ .release = bar_release,
+ .set_frontend = bar_set_frontend,
+ .get_frontend = bar_get_frontend,
+ .read_status = bar_get_status_and_stats,
+ .i2c_gate_ctrl = bar_i2c_gate_ctrl,
+ .get_frontend_algo = bar_get_algo,
+ .tune = bar_tune,
+
+ /* Satellite-specific */
+ .diseqc_send_master_cmd = bar_send_diseqc_msg,
+ .diseqc_send_burst = bar_send_burst,
+ .set_tone = bar_set_tone,
+ .set_voltage = bar_set_voltage,
+ };
+
+.. note::
+
+ #) For satellite digital TV standards (DVB-S, DVB-S2, ISDB-S), the
+ frequencies are specified in kHz, while, for terrestrial and cable
+ standards, they're specified in Hz. Due to that, if the same frontend
+ supports both types, you'll need to have two separate
+ :c:type:`dvb_frontend_ops` structures, one for each standard.
+ #) The ``.i2c_gate_ctrl`` field is present only when the hardware has
+ allows controlling an I2C gate (either directly of via some GPIO pin),
+ in order to remove the tuner from the I2C bus after a channel is
+ tuned.
+ #) All new drivers should implement the
+ :ref:`DVBv5 statistics <dvbv5_stats>` via ``.read_status``.
+ Yet, there are a number of callbacks meant to get statistics for
+ signal strength, S/N and UCB. Those are there to provide backward
+ compatibility with legacy applications that don't support the DVBv5
+ API. Implementing those callbacks are optional. Those callbacks may be
+ removed in the future, after we have all existing drivers supporting
+ DVBv5 stats.
+ #) Other callbacks are required for satellite TV standards, in order to
+ control LNBf and DiSEqC: ``.diseqc_send_master_cmd``,
+ ``.diseqc_send_burst``, ``.set_tone``, ``.set_voltage``.
+
+.. |delta| unicode:: U+00394
+
+The ``drivers/media/dvb-core/dvb_frontend.c`` has a kernel thread with is
+responsible for tuning the device. It supports multiple algoritms to
+detect a channel, as defined at enum :c:func:`dvbfe_algo`.
+
+The algorithm to be used is obtained via ``.get_frontend_algo``. If the driver
+doesn't fill its field at struct :c:type:`dvb_frontend_ops`, it will default to
+``DVBFE_ALGO_SW``, meaning that the dvb-core will do a zigzag when tuning,
+e. g. it will try first to use the specified center frequency ``f``,
+then, it will do ``f`` + |delta|, ``f`` - |delta|, ``f`` + 2 x |delta|,
+``f`` - 2 x |delta| and so on.
+
+If the hardware has internally a some sort of zigzag algorithm, you should
+define a ``.get_frontend_algo`` function that would return ``DVBFE_ALGO_HW``.
+
+.. note::
+
+ The core frontend support also supports
+ a third type (``DVBFE_ALGO_CUSTOM``), in order to allow the driver to
+ define its own hardware-assisted algorithm. Very few hardware need to
+ use it nowadays. Using ``DVBFE_ALGO_CUSTOM`` require to provide other
+ function callbacks at struct :c:type:`dvb_frontend_ops`.
+
+Attaching frontend driver to the bridge driver
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Before using the Digital TV frontend core, the bridge driver should attach
the frontend demod, tuner and SEC devices and call
A few other optional functions are provided to handle some special cases.
+.. _dvbv5_stats:
+
+Digital TV Frontend statistics
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Introduction
+^^^^^^^^^^^^
+
+Digital TV frontends provide a range of
+:ref:`statistics <frontend-stat-properties>` meant to help tuning the device
+and measuring the quality of service.
+
+For each statistics measurement, the driver should set the type of scale used,
+or ``FE_SCALE_NOT_AVAILABLE`` if the statistics is not available on a given
+time. Drivers should also provide the number of statistics for each type.
+that's usually 1 for most video standards [#f2]_.
+
+Drivers should initialize each statistic counters with length and
+scale at its init code. For example, if the frontend provides signal
+strength, it should have, on its init code::
+
+ struct dtv_frontend_properties *c = &state->fe.dtv_property_cache;
+
+ c->strength.len = 1;
+ c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+And, when the statistics got updated, set the scale::
+
+ c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+ c->strength.stat[0].uvalue = strength;
+
+.. [#f2] For ISDB-T, it may provide both a global statistics and a per-layer
+ set of statistics. On such cases, len should be equal to 4. The first
+ value corresponds to the global stat; the other ones to each layer, e. g.:
+
+ - c->cnr.stat[0] for global S/N carrier ratio,
+ - c->cnr.stat[1] for Layer A S/N carrier ratio,
+ - c->cnr.stat[2] for layer B S/N carrier ratio,
+ - c->cnr.stat[3] for layer C S/N carrier ratio.
+
+.. note:: Please prefer to use ``FE_SCALE_DECIBEL`` instead of
+ ``FE_SCALE_RELATIVE`` for signal strength and CNR measurements.
+
+Groups of statistics
+^^^^^^^^^^^^^^^^^^^^
+
+There are several groups of statistics currently supported:
+
+Signal strength (:ref:`DTV-STAT-SIGNAL-STRENGTH`)
+ - Measures the signal strength level at the analog part of the tuner or
+ demod.
+
+ - Typically obtained from the gain applied to the tuner and/or frontend
+ in order to detect the carrier. When no carrier is detected, the gain is
+ at the maximum value (so, strength is on its minimal).
+
+ - As the gain is visible through the set of registers that adjust the gain,
+ typically, this statistics is always available [#f3]_.
+
+ - Drivers should try to make it available all the times, as this statistics
+ can be used when adjusting an antenna position and to check for troubles
+ at the cabling.
+
+ .. [#f3] On a few devices, the gain keeps floating if no carrier.
+ On such devices, strength report should check first if carrier is
+ detected at the tuner (``FE_HAS_CARRIER``, see :c:type:`fe_status`),
+ and otherwise return the lowest possible value.
+
+Carrier Signal to Noise ratio (:ref:`DTV-STAT-CNR`)
+ - Signal to Noise ratio for the main carrier.
+
+ - Signal to Noise measurement depends on the device. On some hardware, is
+ available when the main carrier is detected. On those hardware, CNR
+ measurement usually comes from the tuner (e. g. after ``FE_HAS_CARRIER``,
+ see :c:type:`fe_status`).
+
+ On other devices, it requires inner FEC decoding,
+ as the frontend measures it indirectly from other parameters (e. g. after
+ ``FE_HAS_VITERBI``, see :c:type:`fe_status`).
+
+ Having it available after inner FEC is more common.
+
+Bit counts post-FEC (:ref:`DTV-STAT-POST-ERROR-BIT-COUNT` and :ref:`DTV-STAT-POST-TOTAL-BIT-COUNT`)
+ - Those counters measure the number of bits and bit errors errors after
+ the forward error correction (FEC) on the inner coding block
+ (after Viterbi, LDPC or other inner code).
+
+ - Due to its nature, those statistics depend on full coding lock
+ (e. g. after ``FE_HAS_SYNC`` or after ``FE_HAS_LOCK``,
+ see :c:type:`fe_status`).
+
+Bit counts pre-FEC (:ref:`DTV-STAT-PRE-ERROR-BIT-COUNT` and :ref:`DTV-STAT-PRE-TOTAL-BIT-COUNT`)
+ - Those counters measure the number of bits and bit errors errors before
+ the forward error correction (FEC) on the inner coding block
+ (before Viterbi, LDPC or other inner code).
+
+ - Not all frontends provide this kind of statistics.
+
+ - Due to its nature, those statistics depend on inner coding lock (e. g.
+ after ``FE_HAS_VITERBI``, see :c:type:`fe_status`).
+
+Block counts (:ref:`DTV-STAT-ERROR-BLOCK-COUNT` and :ref:`DTV-STAT-TOTAL-BLOCK-COUNT`)
+ - Those counters measure the number of blocks and block errors errors after
+ the forward error correction (FEC) on the inner coding block
+ (before Viterbi, LDPC or other inner code).
+
+ - Due to its nature, those statistics depend on full coding lock
+ (e. g. after ``FE_HAS_SYNC`` or after
+ ``FE_HAS_LOCK``, see :c:type:`fe_status`).
+
+.. note:: All counters should be monotonically increased as they're
+ collected from the hardware.
+
+A typical example of the logic that handle status and statistics is::
+
+ static int foo_get_status_and_stats(struct dvb_frontend *fe)
+ {
+ struct foo_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+ int rc;
+ enum fe_status *status;
+
+ /* Both status and strength are always available */
+ rc = foo_read_status(fe, &status);
+ if (rc < 0)
+ return rc;
+
+ rc = foo_read_strength(fe);
+ if (rc < 0)
+ return rc;
+
+ /* Check if CNR is available */
+ if (!(fe->status & FE_HAS_CARRIER))
+ return 0;
+
+ rc = foo_read_cnr(fe);
+ if (rc < 0)
+ return rc;
+
+ /* Check if pre-BER stats are available */
+ if (!(fe->status & FE_HAS_VITERBI))
+ return 0;
+
+ rc = foo_get_pre_ber(fe);
+ if (rc < 0)
+ return rc;
+
+ /* Check if post-BER stats are available */
+ if (!(fe->status & FE_HAS_SYNC))
+ return 0;
+
+ rc = foo_get_post_ber(fe);
+ if (rc < 0)
+ return rc;
+ }
+
+ static const struct dvb_frontend_ops ops = {
+ /* ... */
+ .read_status = foo_get_status_and_stats,
+ };
+
+Statistics collect
+^^^^^^^^^^^^^^^^^^
+
+On almost all frontend hardware, the bit and byte counts are stored by
+the hardware after a certain amount of time or after the total bit/block
+counter reaches a certain value (usually programable), for example, on
+every 1000 ms or after receiving 1,000,000 bits.
+
+So, if you read the registers too soon, you'll end by reading the same
+value as in the previous reading, causing the monotonic value to be
+incremented too often.
+
+Drivers should take the responsibility to avoid too often reads. That
+can be done using two approaches:
+
+if the driver have a bit that indicates when a collected data is ready
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Driver should check such bit before making the statistics available.
+
+An example of such behavior can be found at this code snippet (adapted
+from mb86a20s driver's logic)::
+
+ static int foo_get_pre_ber(struct dvb_frontend *fe)
+ {
+ struct foo_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int rc, bit_error;
+
+ /* Check if the BER measures are already available */
+ rc = foo_read_u8(state, 0x54);
+ if (rc < 0)
+ return rc;
+
+ if (!rc)
+ return 0;
+
+ /* Read Bit Error Count */
+ bit_error = foo_read_u32(state, 0x55);
+ if (bit_error < 0)
+ return bit_error;
+
+ /* Read Total Bit Count */
+ rc = foo_read_u32(state, 0x51);
+ if (rc < 0)
+ return rc;
+
+ c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->pre_bit_error.stat[0].uvalue += bit_error;
+ c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->pre_bit_count.stat[0].uvalue += rc;
+
+ return 0;
+ }
+
+If the driver doesn't provide a statistics available check bit
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+A few devices, however, may not provide a way to check if the stats are
+available (or the way to check it is unknown). They may not even provide
+a way to directly read the total number of bits or blocks.
+
+On those devices, the driver need to ensure that it won't be reading from
+the register too often and/or estimate the total number of bits/blocks.
+
+On such drivers, a typical routine to get statistics would be like
+(adapted from dib8000 driver's logic)::
+
+ struct foo_state {
+ /* ... */
+
+ unsigned long per_jiffies_stats;
+ }
+
+ static int foo_get_pre_ber(struct dvb_frontend *fe)
+ {
+ struct foo_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int rc, bit_error;
+ u64 bits;
+
+ /* Check if time for stats was elapsed */
+ if (!time_after(jiffies, state->per_jiffies_stats))
+ return 0;
+
+ /* Next stat should be collected in 1000 ms */
+ state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
+
+ /* Read Bit Error Count */
+ bit_error = foo_read_u32(state, 0x55);
+ if (bit_error < 0)
+ return bit_error;
+
+ /*
+ * On this particular frontend, there's no register that
+ * would provide the number of bits per 1000ms sample. So,
+ * some function would calculate it based on DTV properties
+ */
+ bits = get_number_of_bits_per_1000ms(fe);
+
+ c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->pre_bit_error.stat[0].uvalue += bit_error;
+ c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->pre_bit_count.stat[0].uvalue += bits;
+
+ return 0;
+ }
+
+Please notice that, on both cases, we're getting the statistics using the
+:c:type:`dvb_frontend_ops` ``.read_status`` callback. The rationale is that
+the frontend core will automatically call this function periodically
+(usually, 3 times per second, when the frontend is locked).
+
+That warrants that we won't miss to collect a counter and increment the
+monotonic stats at the right time.
+
+Digital TV Frontend functions and types
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
.. kernel-doc:: drivers/media/dvb-core/dvb_frontend.h
EINVAL
The struct :c:type:`v4l2_format` ``type`` field is
invalid or the requested buffer type not supported.
+
+EBUSY
+ The device is busy and cannot change the format. This could be
+ because or the device is streaming or buffers are allocated or
+ queued to the driver. Relevant for :ref:`VIDIOC_S_FMT
+ <VIDIOC_G_FMT>` only.
Authors
-------
-Steve Longerbeam <steve_longerbeam@mentor.com>
-Philipp Zabel <kernel@pengutronix.de>
-Russell King <linux@armlinux.org.uk>
+
+- Steve Longerbeam <steve_longerbeam@mentor.com>
+- Philipp Zabel <kernel@pengutronix.de>
+- Russell King <linux@armlinux.org.uk>
Copyright (C) 2012-2017 Mentor Graphics Inc.
cx88
davinci-vpbe
fimc
+ imx
ivtv
max2175
meye
/* read the buffer size from the CAM */
if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0)
return ret;
- if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ / 10)) != 0)
+ ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ);
+ if (ret != 0)
return ret;
if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2)
return -EIO;
}
buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer);
- if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) {
+ if (buf_free < (ca->slot_info[slot].link_buf_size +
+ DVB_RINGBUFFER_PKTHDRSIZE)) {
status = -EAGAIN;
goto exit;
}
}
- /* check if there is data available */
- if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
- goto exit;
- if (!(status & STATUSREG_DA)) {
- /* no data */
- status = 0;
- goto exit;
- }
-
- /* read the amount of data */
- if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0)
- goto exit;
- bytes_read = status << 8;
- if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0)
- goto exit;
- bytes_read |= status;
+ if (ca->pub->read_data &&
+ (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_LINKINIT)) {
+ if (ebuf == NULL)
+ status = ca->pub->read_data(ca->pub, slot, buf,
+ sizeof(buf));
+ else
+ status = ca->pub->read_data(ca->pub, slot, buf, ecount);
+ if (status < 0)
+ return status;
+ bytes_read = status;
+ if (status == 0)
+ goto exit;
+ } else {
- /* check it will fit */
- if (ebuf == NULL) {
- if (bytes_read > ca->slot_info[slot].link_buf_size) {
- pr_err("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n",
- ca->dvbdev->adapter->num, bytes_read,
- ca->slot_info[slot].link_buf_size);
- ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
- status = -EIO;
+ /* check if there is data available */
+ status = ca->pub->read_cam_control(ca->pub, slot,
+ CTRLIF_STATUS);
+ if (status < 0)
goto exit;
- }
- if (bytes_read < 2) {
- pr_err("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n",
- ca->dvbdev->adapter->num);
- ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
- status = -EIO;
+ if (!(status & STATUSREG_DA)) {
+ /* no data */
+ status = 0;
goto exit;
}
- } else {
- if (bytes_read > ecount) {
- pr_err("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n",
- ca->dvbdev->adapter->num);
- status = -EIO;
+
+ /* read the amount of data */
+ status = ca->pub->read_cam_control(ca->pub, slot,
+ CTRLIF_SIZE_HIGH);
+ if (status < 0)
+ goto exit;
+ bytes_read = status << 8;
+ status = ca->pub->read_cam_control(ca->pub, slot,
+ CTRLIF_SIZE_LOW);
+ if (status < 0)
goto exit;
+ bytes_read |= status;
+
+ /* check it will fit */
+ if (ebuf == NULL) {
+ if (bytes_read > ca->slot_info[slot].link_buf_size) {
+ pr_err("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n",
+ ca->dvbdev->adapter->num, bytes_read,
+ ca->slot_info[slot].link_buf_size);
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_LINKINIT;
+ status = -EIO;
+ goto exit;
+ }
+ if (bytes_read < 2) {
+ pr_err("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n",
+ ca->dvbdev->adapter->num);
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_LINKINIT;
+ status = -EIO;
+ goto exit;
+ }
+ } else {
+ if (bytes_read > ecount) {
+ pr_err("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n",
+ ca->dvbdev->adapter->num);
+ status = -EIO;
+ goto exit;
+ }
}
- }
- /* fill the buffer */
- for (i = 0; i < bytes_read; i++) {
- /* read byte and check */
- if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0)
- goto exit;
+ /* fill the buffer */
+ for (i = 0; i < bytes_read; i++) {
+ /* read byte and check */
+ status = ca->pub->read_cam_control(ca->pub, slot,
+ CTRLIF_DATA);
+ if (status < 0)
+ goto exit;
- /* OK, store it in the buffer */
- buf[i] = status;
- }
+ /* OK, store it in the buffer */
+ buf[i] = status;
+ }
- /* check for read error (RE should now be 0) */
- if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
- goto exit;
- if (status & STATUSREG_RE) {
- ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
- status = -EIO;
- goto exit;
+ /* check for read error (RE should now be 0) */
+ status = ca->pub->read_cam_control(ca->pub, slot,
+ CTRLIF_STATUS);
+ if (status < 0)
+ goto exit;
+ if (status & STATUSREG_RE) {
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_LINKINIT;
+ status = -EIO;
+ goto exit;
+ }
}
/* OK, add it to the receive buffer, or copy into external buffer if supplied */
if (bytes_write > ca->slot_info[slot].link_buf_size)
return -EINVAL;
+ if (ca->pub->write_data &&
+ (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_LINKINIT))
+ return ca->pub->write_data(ca->pub, slot, buf, bytes_write);
+
/* it is possible we are dealing with a single buffer implementation,
thus if there is data available for read or if there is even a read
already in progress, we do nothing but awake the kernel thread to
pr_err("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n",
ca->dvbdev->adapter->num);
- ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_UNINITIALISED;
dvb_ca_en50221_thread_update_delay(ca);
break;
}
* @write_attribute_mem: function for writing attribute memory on the CAM
* @read_cam_control: function for reading the control interface on the CAM
* @write_cam_control: function for reading the control interface on the CAM
+ * @read_data: function for reading data (block mode)
+ * @write_data: function for writing data (block mode)
* @slot_reset: function to reset the CAM slot
* @slot_shutdown: function to shutdown a CAM slot
* @slot_ts_enable: function to enable the Transport Stream on a CAM slot
int (*write_cam_control)(struct dvb_ca_en50221 *ca,
int slot, u8 address, u8 value);
+ int (*read_data)(struct dvb_ca_en50221 *ca,
+ int slot, u8 *ebuf, int ecount);
+ int (*write_data)(struct dvb_ca_en50221 *ca,
+ int slot, u8 *ebuf, int ecount);
+
int (*slot_reset)(struct dvb_ca_en50221 *ca, int slot);
int (*slot_shutdown)(struct dvb_ca_en50221 *ca, int slot);
int (*slot_ts_enable)(struct dvb_ca_en50221 *ca, int slot);
else if (priv->state == STATE_ACTIVE_TC)
cxd2841er_read_status_tc(fe, &status);
- cxd2841er_read_signal_strength(fe);
+ if (priv->state == STATE_ACTIVE_TC || priv->state == STATE_ACTIVE_S)
+ cxd2841er_read_signal_strength(fe);
+ else
+ p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
if (status & FE_HAS_LOCK) {
cxd2841er_read_snr(fe);
* \def DRX_UNKNOWN
* \brief Generic UNKNOWN value for DRX enumerated types.
*
-* Used to indicate that the parameter value is unknown or not yet initalized.
+* Used to indicate that the parameter value is unknown or not yet initialized.
*/
#ifndef DRX_UNKNOWN
#define DRX_UNKNOWN (254)
#define DRX_16TO8(x) ((u8) (((u16)x) & 0xFF)), \
((u8)((((u16)x)>>8)&0xFF))
-/**
-* \brief Macro to sign extend signed 9 bit value to signed 16 bit value
-*/
-#define DRX_S9TOS16(x) ((((u16)x)&0x100) ? ((s16)((u16)(x)|0xFF00)) : (x))
-
-/**
-* \brief Macro to sign extend signed 9 bit value to signed 16 bit value
-*/
-#define DRX_S24TODRXFREQ(x) ((((u32) x) & 0x00800000UL) ? \
- ((s32) \
- (((u32) x) | 0xFF000000)) : \
- ((s32) x))
-
/**
* \brief Macro to convert 16 bit register value to a s32
*/
return ret;
}
}
- print_hex_dump_bytes("lnbh25_read_vmon: ",
- DUMP_PREFIX_OFFSET, status, sizeof(status));
+ dev_dbg(&priv->i2c->dev, "%s(): %*ph\n",
+ __func__, (int) sizeof(status), status);
if ((status[0] & (LNBH25_STATUS_OFL | LNBH25_STATUS_VMON)) != 0) {
dev_err(&priv->i2c->dev,
"%s(): voltage in failure state, status reg 0x%x\n",
fe->ops.release_sec = lnbh25_release;
fe->ops.set_voltage = lnbh25_set_voltage;
- dev_err(&i2c->dev, "%s(): attached at I2C addr 0x%02x\n",
+ dev_info(&i2c->dev, "%s(): attached at I2C addr 0x%02x\n",
__func__, priv->i2c_address);
return fe;
}
#include <linux/slab.h>
#include <linux/i2c.h>
+#include "dvb_math.h"
+
#include "stv0367.h"
#include "stv0367_defs.h"
#include "stv0367_regs.h"
return 0;
}
-static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr)
+static u32 stv0367ter_snr_readreg(struct dvb_frontend *fe)
{
struct stv0367_state *state = fe->demodulator_priv;
u32 snru32 = 0;
cpt++;
}
-
snru32 /= 10;/*average on 10 values*/
- *snr = snru32 / 1000;
+ return snru32;
+}
+
+static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ u32 snrval = stv0367ter_snr_readreg(fe);
+
+ *snr = snrval / 1000;
return 0;
}
*status = 0;
if (stv0367_readbits(state, F367TER_LK)) {
- *status |= FE_HAS_LOCK;
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI
+ | FE_HAS_SYNC | FE_HAS_LOCK;
dprintk("%s: stv0367 has locked\n", __func__);
}
*status = 0;
+ if (state->cab_state->state > FE_CAB_NOSIGNAL)
+ *status |= FE_HAS_SIGNAL;
+
+ if (state->cab_state->state > FE_CAB_NOCARRIER)
+ *status |= FE_HAS_CARRIER;
+
+ if (state->cab_state->state >= FE_CAB_DEMODOK)
+ *status |= FE_HAS_VITERBI;
+
+ if (state->cab_state->state >= FE_CAB_DATAOK)
+ *status |= FE_HAS_SYNC;
+
if (stv0367_readbits(state, (state->cab_state->qamfec_status_reg ?
state->cab_state->qamfec_status_reg : F367CAB_QAMFEC_LOCK))) {
*status |= FE_HAS_LOCK;
return 0;
}
-static int stv0367cab_read_snr(struct dvb_frontend *fe, u16 *snr)
+static int stv0367cab_snr_power(struct dvb_frontend *fe)
{
struct stv0367_state *state = fe->demodulator_priv;
- u32 noisepercentage;
enum stv0367cab_mod QAMSize;
- u32 regval = 0, temp = 0;
- int power, i;
QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE);
switch (QAMSize) {
case FE_CAB_MOD_QAM4:
- power = 21904;
- break;
+ return 21904;
case FE_CAB_MOD_QAM16:
- power = 20480;
- break;
+ return 20480;
case FE_CAB_MOD_QAM32:
- power = 23040;
- break;
+ return 23040;
case FE_CAB_MOD_QAM64:
- power = 21504;
- break;
+ return 21504;
case FE_CAB_MOD_QAM128:
- power = 23616;
- break;
+ return 23616;
case FE_CAB_MOD_QAM256:
- power = 21760;
- break;
- case FE_CAB_MOD_QAM512:
- power = 1;
- break;
+ return 21760;
case FE_CAB_MOD_QAM1024:
- power = 21280;
- break;
+ return 21280;
default:
- power = 1;
break;
}
+ return 1;
+}
+
+static int stv0367cab_snr_readreg(struct dvb_frontend *fe, int avgdiv)
+{
+ struct stv0367_state *state = fe->demodulator_priv;
+ u32 regval = 0;
+ int i;
+
for (i = 0; i < 10; i++) {
regval += (stv0367_readbits(state, F367CAB_SNR_LO)
+ 256 * stv0367_readbits(state, F367CAB_SNR_HI));
}
- regval /= 10; /*for average over 10 times in for loop above*/
+ if (avgdiv)
+ regval /= 10;
+
+ return regval;
+}
+
+static int stv0367cab_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct stv0367_state *state = fe->demodulator_priv;
+ u32 noisepercentage;
+ u32 regval = 0, temp = 0;
+ int power;
+
+ power = stv0367cab_snr_power(fe);
+ regval = stv0367cab_snr_readreg(fe, 1);
+
if (regval != 0) {
temp = power
* (1 << (3 + stv0367_readbits(state, F367CAB_SNR_PER)));
return -EINVAL;
}
+static void stv0367ddb_read_signal_strength(struct dvb_frontend *fe)
+{
+ struct stv0367_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ s32 signalstrength;
+
+ switch (state->activedemod) {
+ case demod_cab:
+ signalstrength = stv0367cab_get_rf_lvl(state) * 1000;
+ break;
+ default:
+ p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ return;
+ }
+
+ p->strength.stat[0].scale = FE_SCALE_DECIBEL;
+ p->strength.stat[0].uvalue = signalstrength;
+}
+
+static void stv0367ddb_read_snr(struct dvb_frontend *fe)
+{
+ struct stv0367_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ int cab_pwr;
+ u32 regval, tmpval, snrval = 0;
+
+ switch (state->activedemod) {
+ case demod_ter:
+ snrval = stv0367ter_snr_readreg(fe);
+ break;
+ case demod_cab:
+ cab_pwr = stv0367cab_snr_power(fe);
+ regval = stv0367cab_snr_readreg(fe, 0);
+
+ /* prevent division by zero */
+ if (!regval) {
+ snrval = 0;
+ break;
+ }
+
+ tmpval = (cab_pwr * 320) / regval;
+ snrval = ((tmpval != 0) ? (intlog2(tmpval) / 5581) : 0);
+ break;
+ default:
+ p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ return;
+ }
+
+ p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+ p->cnr.stat[0].uvalue = snrval;
+}
+
+static void stv0367ddb_read_ucblocks(struct dvb_frontend *fe)
+{
+ struct stv0367_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ u32 ucblocks = 0;
+
+ switch (state->activedemod) {
+ case demod_ter:
+ stv0367ter_read_ucblocks(fe, &ucblocks);
+ break;
+ case demod_cab:
+ stv0367cab_read_ucblcks(fe, &ucblocks);
+ break;
+ default:
+ p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ return;
+ }
+
+ p->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ p->block_error.stat[0].uvalue = ucblocks;
+}
+
static int stv0367ddb_read_status(struct dvb_frontend *fe,
enum fe_status *status)
{
struct stv0367_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ int ret;
switch (state->activedemod) {
case demod_ter:
- return stv0367ter_read_status(fe, status);
+ ret = stv0367ter_read_status(fe, status);
+ break;
case demod_cab:
- return stv0367cab_read_status(fe, status);
- default:
+ ret = stv0367cab_read_status(fe, status);
break;
+ default:
+ return 0;
}
- return -EINVAL;
+ /* stop and report on *_read_status failure */
+ if (ret)
+ return ret;
+
+ stv0367ddb_read_signal_strength(fe);
+
+ /* read carrier/noise when a carrier is detected */
+ if (*status & FE_HAS_CARRIER)
+ stv0367ddb_read_snr(fe);
+ else
+ p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+ /* read uncorrected blocks on FE_HAS_LOCK */
+ if (*status & FE_HAS_LOCK)
+ stv0367ddb_read_ucblocks(fe);
+ else
+ p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+ return 0;
}
static int stv0367ddb_get_frontend(struct dvb_frontend *fe,
static int stv0367ddb_init(struct stv0367_state *state)
{
struct stv0367ter_state *ter_state = state->ter_state;
+ struct dtv_frontend_properties *p = &state->fe.dtv_property_cache;
stv0367_writereg(state, R367TER_TOPCTRL, 0x10);
ter_state->first_lock = 0;
ter_state->unlock_counter = 2;
+ p->strength.len = 1;
+ p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->cnr.len = 1;
+ p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_error.len = 1;
+ p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
return 0;
}
0x400 |/* FE_CAN_QAM_4 */
FE_CAN_QAM_16 | FE_CAN_QAM_32 |
FE_CAN_QAM_64 | FE_CAN_QAM_128 |
- FE_CAN_QAM_256 | FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_256 | FE_CAN_QAM_AUTO |
/* DVB-T */
- FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
- FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
- FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
- FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER |
- FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_RECOVER | FE_CAN_INVERSION_AUTO |
FE_CAN_MUTE_TS
},
.release = stv0367_release,
static const struct dev_pm_ops et8ek8_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(et8ek8_suspend, et8ek8_resume)
};
-MODULE_DEVICE_TABLE(of, et8ek8_of_table);
static struct i2c_driver et8ek8_i2c_driver = {
.driver = {
struct tvp5150 *decoder = to_tvp5150(sd);
v4l2_std_id std = decoder->norm;
u8 reg;
- int pos=0;
+ int pos = 0;
if (std == V4L2_STD_ALL) {
dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n");
line += 3;
}
- if (line<6||line>27)
+ if (line < 6 || line > 27)
return 0;
- while (regs->reg != (u16)-1 ) {
+ while (regs->reg != (u16)-1) {
if ((type & regs->type.vbi_type) &&
- (line>=regs->type.ini_line) &&
- (line<=regs->type.end_line)) {
- type=regs->type.vbi_type;
+ (line >= regs->type.ini_line) &&
+ (line <= regs->type.end_line))
break;
- }
regs++;
pos++;
}
+
if (regs->reg == (u16)-1)
return 0;
- type=pos | (flags & 0xf0);
- reg=((line-6)<<1)+TVP5150_LINE_MODE_INI;
+ type = pos | (flags & 0xf0);
+ reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI;
- if (fields&1) {
+ if (fields & 1)
tvp5150_write(sd, reg, type);
- }
- if (fields&2) {
- tvp5150_write(sd, reg+1, type);
- }
+ if (fields & 2)
+ tvp5150_write(sd, reg + 1, type);
return type;
}
* http://www.gnu.org/copyleft/gpl.html
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
return i2c_write(adap, adr, msg, 2);
}
+static inline u32 safe_ddbreadl(struct ddb *dev, u32 adr)
+{
+ u32 val = ddbreadl(adr);
+
+ /* (ddb)readl returns (uint)-1 (all bits set) on failure, catch that */
+ if (val == ~0) {
+ dev_err(&dev->pdev->dev, "ddbreadl failure, adr=%08x\n", adr);
+ return 0;
+ }
+
+ return val;
+}
+
static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
{
struct ddb *dev = i2c->dev;
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");
+ dev_err(&dev->pdev->dev, "I2C timeout\n");
{ /* MSI debugging*/
u32 istat = ddbreadl(INTERRUPT_STATUS);
- printk(KERN_ERR "IRS %08x\n", istat);
+ dev_err(&dev->pdev->dev, "IRS %08x\n", istat);
ddbwritel(istat, INTERRUPT_ACK);
}
return -EIO;
off = (stat & 0x7ff) << 7;
if (ctrl & 4) {
- printk(KERN_ERR "IA %d %d %08x\n", idx, off, ctrl);
+ dev_err(&dev->pdev->dev, "IA %d %d %08x\n", idx, off, ctrl);
ddbwritel(input->stat, DMA_BUFFER_ACK(input->nr));
return 0;
}
struct i2c_adapter *i2c = &input->port->i2c->adap;
struct dvb_frontend *fe;
struct drxk_config config;
+ struct device *dev = &input->port->dev->pdev->dev;
memset(&config, 0, sizeof(config));
config.microcode_name = "drxk_a3.mc";
fe = input->fe = dvb_attach(drxk_attach, &config, i2c);
if (!input->fe) {
- printk(KERN_ERR "No DRXK found!\n");
+ dev_err(dev, "No DRXK found!\n");
return -ENODEV;
}
fe->sec_priv = input;
{
struct i2c_adapter *i2c = &input->port->i2c->adap;
struct dvb_frontend *fe;
+ struct device *dev = &input->port->dev->pdev->dev;
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");
+ dev_err(dev, "No TDA18271 found!\n");
return -ENODEV;
}
if (input->fe->ops.i2c_gate_ctrl)
static int demod_attach_stv0367(struct ddb_input *input)
{
struct i2c_adapter *i2c = &input->port->i2c->adap;
+ struct device *dev = &input->port->dev->pdev->dev;
/* attach frontend */
input->fe = dvb_attach(stv0367ddb_attach,
&ddb_stv0367_config[(input->nr & 1)], i2c);
if (!input->fe) {
- printk(KERN_ERR "stv0367ddb_attach failed (not found?)\n");
+ dev_err(dev, "stv0367ddb_attach failed (not found?)\n");
return -ENODEV;
}
static int tuner_tda18212_ping(struct ddb_input *input, unsigned short adr)
{
struct i2c_adapter *adapter = &input->port->i2c->adap;
+ struct device *dev = &input->port->dev->pdev->dev;
+
u8 tda_id[2];
u8 subaddr = 0x00;
- printk(KERN_DEBUG "stv0367-tda18212 tuner ping\n");
+ dev_dbg(dev, "stv0367-tda18212 tuner ping\n");
if (input->fe->ops.i2c_gate_ctrl)
input->fe->ops.i2c_gate_ctrl(input->fe, 1);
if (i2c_read_regs(adapter, adr, subaddr, tda_id, sizeof(tda_id)) < 0)
- printk(KERN_DEBUG "tda18212 ping 1 fail\n");
+ dev_dbg(dev, "tda18212 ping 1 fail\n");
if (i2c_read_regs(adapter, adr, subaddr, tda_id, sizeof(tda_id)) < 0)
- printk(KERN_DEBUG "tda18212 ping 2 fail\n");
+ dev_warn(dev, "tda18212 ping failed, expect problems\n");
if (input->fe->ops.i2c_gate_ctrl)
input->fe->ops.i2c_gate_ctrl(input->fe, 0);
static int demod_attach_cxd28xx(struct ddb_input *input, int par, int osc24)
{
struct i2c_adapter *i2c = &input->port->i2c->adap;
+ struct device *dev = &input->port->dev->pdev->dev;
struct cxd2841er_config cfg;
/* the cxd2841er driver expects 8bit/shifted I2C addresses */
input->fe = dvb_attach(cxd2841er_attach_t_c, &cfg, i2c);
if (!input->fe) {
- printk(KERN_ERR "No Sony CXD28xx found!\n");
+ dev_err(dev, "No Sony CXD28xx found!\n");
return -ENODEV;
}
static int tuner_attach_tda18212(struct ddb_input *input, u32 porttype)
{
struct i2c_adapter *adapter = &input->port->i2c->adap;
+ struct device *dev = &input->port->dev->pdev->dev;
struct i2c_client *client;
struct tda18212_config config = {
.fe = input->fe,
return 0;
err:
- printk(KERN_INFO "TDA18212 tuner not found. Device is not fully operational.\n");
+ dev_warn(dev, "TDA18212 tuner not found. Device is not fully operational.\n");
return -ENODEV;
}
static int demod_attach_stv0900(struct ddb_input *input, int type)
{
struct i2c_adapter *i2c = &input->port->i2c->adap;
+ struct device *dev = &input->port->dev->pdev->dev;
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");
+ dev_err(dev, "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");
+ dev_err(dev, "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 device *dev = &input->port->dev->pdev->dev;
struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900;
struct stv6110x_config *tunerconf = (input->nr & 1) ?
&stv6110b : &stv6110a;
ctl = dvb_attach(stv6110x_attach, input->fe, tunerconf, i2c);
if (!ctl) {
- printk(KERN_ERR "No STV6110X found!\n");
+ dev_err(dev, "No STV6110X found!\n");
return -ENODEV;
}
- printk(KERN_INFO "attach tuner input %d adr %02x\n",
+ dev_info(dev, "attach tuner input %d adr %02x\n",
input->nr, tunerconf->addr);
feconf->tuner_init = ctl->tuner_init;
struct ddb_port *port = input->port;
struct dvb_adapter *adap = &input->adap;
struct dvb_demux *dvbdemux = &input->demux;
+ struct device *dev = &input->port->dev->pdev->dev;
int sony_osc24 = 0, sony_tspar = 0;
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");
+ dev_err(dev, "Could not register adapter. Check if you enabled enough adapters in dvb-core!\n");
return ret;
}
input->attached = 1;
if (input->port->class == DDB_PORT_TUNER) {
if (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr)))
- printk(KERN_ERR "Overflow input %d\n", input->nr);
+ dev_err(&dev->pdev->dev, "Overflow input %d\n", input->nr);
while (input->cbuf != ((input->stat >> 11) & 0x1f)
- || (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr)))) {
+ || (4 & safe_ddbreadl(dev, DMA_BUFFER_CONTROL(input->nr)))) {
dvb_dmx_swfilter_packets(&input->demux,
input->vbuf[input->cbuf],
input->dma_buf_size / 188);
.adr = 0x40,
.polarity = 1,
.clock_mode = 1,
+ .max_i2c = 512,
};
static int ddb_ci_attach(struct ddb_port *port)
static int ddb_port_attach(struct ddb_port *port)
{
+ struct device *dev = &port->dev->pdev->dev;
int ret = 0;
switch (port->class) {
break;
}
if (ret < 0)
- printk(KERN_ERR "port_attach on port %d failed\n", port->nr);
+ dev_err(dev, "port_attach on port %d failed\n", port->nr);
return ret;
}
static int init_xo2(struct ddb_port *port)
{
struct i2c_adapter *i2c = &port->i2c->adap;
+ struct device *dev = &port->dev->pdev->dev;
u8 val, data[2];
int res;
return res;
if (data[0] != 0x01) {
- pr_info("Port %d: invalid XO2\n", port->nr);
+ dev_info(dev, "Port %d: invalid XO2\n", port->nr);
return -1;
}
port->class = DDB_PORT_CI;
ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
} else if (port_has_xo2(port, &xo2_type, &xo2_id)) {
- printk(KERN_INFO "Port %d (TAB %d): XO2 type: %d, id: %d\n",
+ dev_dbg(&dev->pdev->dev, "Port %d (TAB %d): XO2 type: %d, id: %d\n",
port->nr, port->nr+1, xo2_type, xo2_id);
ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
}
break;
case DDB_XO2_TYPE_CI:
- printk(KERN_INFO "DuoFlex CI modules not supported\n");
+ dev_info(&dev->pdev->dev, "DuoFlex CI modules not supported\n");
break;
default:
- printk(KERN_INFO "Unknown XO2 DuoFlex module\n");
+ dev_info(&dev->pdev->dev, "Unknown XO2 DuoFlex module\n");
break;
}
} else if (port_has_cxd28xx(port, &cxd_id)) {
ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING);
}
- printk(KERN_INFO "Port %d (TAB %d): %s\n",
+ dev_info(&dev->pdev->dev, "Port %d (TAB %d): %s\n",
port->nr, port->nr+1, modname);
}
wbuf += 4;
wlen -= 4;
ddbwritel(data, SPI_DATA);
- while (ddbreadl(SPI_CONTROL) & 0x0004)
+ while (safe_ddbreadl(dev, SPI_CONTROL) & 0x0004)
;
}
if (shift)
data <<= shift;
ddbwritel(data, SPI_DATA);
- while (ddbreadl(SPI_CONTROL) & 0x0004)
+ while (safe_ddbreadl(dev, SPI_CONTROL) & 0x0004)
;
if (!rlen) {
while (rlen > 4) {
ddbwritel(0xffffffff, SPI_DATA);
- while (ddbreadl(SPI_CONTROL) & 0x0004)
+ while (safe_ddbreadl(dev, SPI_CONTROL) & 0x0004)
;
data = ddbreadl(SPI_DATA);
*(u32 *) rbuf = swab32(data);
}
ddbwritel(0x0003 | ((rlen << (8 + 3)) & 0x1F00), SPI_CONTROL);
ddbwritel(0xffffffff, SPI_DATA);
- while (ddbreadl(SPI_CONTROL) & 0x0004)
+ while (safe_ddbreadl(dev, SPI_CONTROL) & 0x0004)
;
data = ddbreadl(SPI_DATA);
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_info(&pdev->dev, "Detected %s\n", dev->info->name);
dev->regs = ioremap(pci_resource_start(dev->pdev, 0),
pci_resource_len(dev->pdev, 0));
stat = -ENOMEM;
goto fail;
}
- printk(KERN_INFO "HW %08x FW %08x\n", ddbreadl(0), ddbreadl(4));
+ dev_info(&pdev->dev, "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");
+ dev_info(&pdev->dev, "MSI not available.\n");
} else {
irq_flag = 0;
dev->msi = 1;
goto fail1;
ddb_ports_init(dev);
if (ddb_buffers_alloc(dev) < 0) {
- printk(KERN_INFO ": Could not allocate buffer memory\n");
+ dev_err(&pdev->dev, "Could not allocate buffer memory\n");
goto fail2;
}
if (ddb_ports_attach(dev) < 0)
fail3:
ddb_ports_detach(dev);
- printk(KERN_ERR "fail3\n");
+ dev_err(&pdev->dev, "fail3\n");
ddb_ports_release(dev);
fail2:
- printk(KERN_ERR "fail2\n");
+ dev_err(&pdev->dev, "fail2\n");
ddb_buffers_free(dev);
fail1:
- printk(KERN_ERR "fail1\n");
+ dev_err(&pdev->dev, "fail1\n");
if (dev->msi)
pci_disable_msi(dev->pdev);
if (stat == 0)
free_irq(dev->pdev->irq, dev);
fail:
- printk(KERN_ERR "fail\n");
+ dev_err(&pdev->dev, "fail\n");
ddb_unmap(dev);
pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
{
int ret;
- printk(KERN_INFO "Digital Devices PCIE bridge driver, Copyright (C) 2010-11 Digital Devices GmbH\n");
+ pr_info("Digital Devices PCIE bridge driver, Copyright (C) 2010-11 Digital Devices GmbH\n");
ret = ddb_class_create();
if (ret < 0)
{
int result;
- down(&dev->cmd_mutex);
+ mutex_lock(&dev->cmd_mutex);
result = ngene_command_mutex(dev, com);
- up(&dev->cmd_mutex);
+ mutex_unlock(&dev->cmd_mutex);
return result;
}
u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700);
u16 BsSDO = 0x9B00;
- down(&dev->stream_mutex);
memset(&com, 0, sizeof(com));
com.cmd.hdr.Opcode = CMD_CONTROL;
com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2;
chan->State = KSSTATE_ACQUIRE;
chan->HWState = HWSTATE_STOP;
spin_unlock_irq(&chan->state_lock);
- if (ngene_command(dev, &com) < 0) {
- up(&dev->stream_mutex);
+ if (ngene_command(dev, &com) < 0)
return -1;
- }
/* clear_buffers(chan); */
flush_buffers(chan);
- up(&dev->stream_mutex);
return 0;
}
spin_unlock_irq(&chan->state_lock);
- up(&dev->stream_mutex);
return 0;
}
chan->HWState = HWSTATE_STARTUP;
spin_unlock_irq(&chan->state_lock);
- if (ngene_command(dev, &com) < 0) {
- up(&dev->stream_mutex);
+ if (ngene_command(dev, &com) < 0)
return -1;
- }
- up(&dev->stream_mutex);
+
return 0;
}
/* else printk(KERN_INFO DEVICE_NAME ": lock=%08x\n",
ngreadl(0x9310)); */
+ mutex_lock(&dev->stream_mutex);
ret = ngene_command_stream_control(dev, chan->number,
control, mode, flags);
+ mutex_unlock(&dev->stream_mutex);
+
if (!ret)
chan->running = state;
else
static void ngene_stop(struct ngene *dev)
{
- down(&dev->cmd_mutex);
+ mutex_destroy(&dev->cmd_mutex);
i2c_del_adapter(&(dev->channel[0].i2c_adapter));
i2c_del_adapter(&(dev->channel[1].i2c_adapter));
ngwritel(0, NGENE_INT_ENABLE);
init_waitqueue_head(&dev->cmd_wq);
init_waitqueue_head(&dev->tx_wq);
init_waitqueue_head(&dev->rx_wq);
- sema_init(&dev->cmd_mutex, 1);
- sema_init(&dev->stream_mutex, 1);
+ mutex_init(&dev->cmd_mutex);
+ mutex_init(&dev->stream_mutex);
sema_init(&dev->pll_mutex, 1);
- sema_init(&dev->i2c_switch_mutex, 1);
+ mutex_init(&dev->i2c_switch_mutex);
spin_lock_init(&dev->cmd_lock);
for (i = 0; i < MAX_STREAM; i++)
spin_lock_init(&dev->channel[i].state_lock);
com.in_len = 3;
com.out_len = 1;
- down(&dev->cmd_mutex);
+ mutex_lock(&dev->cmd_mutex);
ngwritel(0, NGENE_INT_ENABLE);
ngene_command_mutex(dev, &com);
- up(&dev->cmd_mutex);
+ mutex_unlock(&dev->cmd_mutex);
}
void ngene_shutdown(struct pci_dev *pdev)
(struct ngene_channel *)i2c_get_adapdata(adapter);
struct ngene *dev = chan->dev;
- down(&dev->i2c_switch_mutex);
+ mutex_lock(&dev->i2c_switch_mutex);
ngene_i2c_set_bus(dev, chan->number);
if (num == 2 && msg[1].flags & I2C_M_RD && !(msg[0].flags & I2C_M_RD))
msg[0].buf, msg[0].len, 0))
goto done;
- up(&dev->i2c_switch_mutex);
+ mutex_unlock(&dev->i2c_switch_mutex);
return -EIO;
done:
- up(&dev->i2c_switch_mutex);
+ mutex_unlock(&dev->i2c_switch_mutex);
return num;
}
wait_queue_head_t cmd_wq;
int cmd_done;
- struct semaphore cmd_mutex;
- struct semaphore stream_mutex;
+ struct mutex cmd_mutex;
+ struct mutex stream_mutex;
struct semaphore pll_mutex;
- struct semaphore i2c_switch_mutex;
+ struct mutex i2c_switch_mutex;
int i2c_current_channel;
int i2c_current_bus;
spinlock_t cmd_lock;
switch (input->std) {
default:
WARN_ON_ONCE(1);
+ return -EINVAL;
case STD_NTSC:
f->fmt.pix.height = 480;
break;
int ret;
int i;
- if (ctx->codec && (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 ||
- ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264)) {
+ if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 ||
+ ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264) {
width = round_up(q_data->width, 16);
height = round_up(q_data->height, 16);
} else {
ctx->display_idx = display_idx;
}
-static void coda_error_decode(struct coda_ctx *ctx)
+static void coda_decode_timeout(struct coda_ctx *ctx)
{
struct vb2_v4l2_buffer *dst_buf;
.start_streaming = coda_start_decoding,
.prepare_run = coda_prepare_decode,
.finish_run = coda_finish_decode,
- .error_run = coda_error_decode,
+ .run_timeout = coda_decode_timeout,
.seq_end_work = coda_seq_end_work,
.release = coda_bit_release,
};
coda_hw_reset(ctx);
- if (ctx->ops->error_run)
- ctx->ops->error_run(ctx);
+ if (ctx->ops->run_timeout)
+ ctx->ops->run_timeout(ctx);
} else if (!ctx->aborting) {
ctx->ops->finish_run(ctx);
}
int (*start_streaming)(struct coda_ctx *ctx);
int (*prepare_run)(struct coda_ctx *ctx);
void (*finish_run)(struct coda_ctx *ctx);
- void (*error_run)(struct coda_ctx *ctx);
+ void (*run_timeout)(struct coda_ctx *ctx);
void (*seq_end_work)(struct work_struct *work);
void (*release)(struct coda_ctx *ctx);
};
#include <media/videobuf-dma-contig.h>
#include <media/v4l2-device.h>
-#include <linux/omap-dma.h>
#include <video/omapvrfb.h>
#include "omap_voutdef.h"
/*
* Wakes up the application once the DMA transfer to VRFB space is completed.
*/
-static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data)
+static void omap_vout_vrfb_dma_tx_callback(void *data)
{
struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data;
int ret = 0, i, j;
struct omap_vout_device *vout;
struct video_device *vfd;
+ dma_cap_mask_t mask;
int image_width, image_height;
int vrfb_num_bufs = VRFB_NUM_BUFS;
struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
/*
* Request and Initialize DMA, for DMA based VRFB transfer
*/
- vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE;
- vout->vrfb_dma_tx.dma_ch = -1;
- vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED;
- ret = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX",
- omap_vout_vrfb_dma_tx_callback,
- (void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch);
- if (ret < 0) {
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_INTERLEAVE, mask);
+ vout->vrfb_dma_tx.chan = dma_request_chan_by_mask(&mask);
+ if (IS_ERR(vout->vrfb_dma_tx.chan)) {
vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
+ } else {
+ size_t xt_size = sizeof(struct dma_interleaved_template) +
+ sizeof(struct data_chunk);
+
+ vout->vrfb_dma_tx.xt = kzalloc(xt_size, GFP_KERNEL);
+ if (!vout->vrfb_dma_tx.xt) {
+ dma_release_channel(vout->vrfb_dma_tx.chan);
+ vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
+ }
+ }
+
+ if (vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED)
dev_info(&pdev->dev,
": failed to allocate DMA Channel for video%d\n",
vfd->minor);
- }
+
init_waitqueue_head(&vout->vrfb_dma_tx.wait);
/* statically allocated the VRFB buffer is done through
if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) {
vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
- omap_free_dma(vout->vrfb_dma_tx.dma_ch);
+ kfree(vout->vrfb_dma_tx.xt);
+ dmaengine_terminate_sync(vout->vrfb_dma_tx.chan);
+ dma_release_channel(vout->vrfb_dma_tx.chan);
}
}
}
int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
- struct videobuf_buffer *vb)
+ struct videobuf_buffer *vb)
{
- dma_addr_t dmabuf;
- struct vid_vrfb_dma *tx;
+ struct dma_async_tx_descriptor *tx;
+ enum dma_ctrl_flags flags;
+ struct dma_chan *chan = vout->vrfb_dma_tx.chan;
+ struct dma_device *dmadev = chan->device;
+ struct dma_interleaved_template *xt = vout->vrfb_dma_tx.xt;
+ dma_cookie_t cookie;
+ enum dma_status status;
enum dss_rotation rotation;
- u32 dest_frame_index = 0, src_element_index = 0;
- u32 dest_element_index = 0, src_frame_index = 0;
- u32 elem_count = 0, frame_count = 0, pixsize = 2;
+ size_t dst_icg;
+ u32 pixsize;
if (!is_rotation_enabled(vout))
return 0;
- dmabuf = vout->buf_phy_addr[vb->i];
/* If rotation is enabled, copy input buffer into VRFB
* memory space using DMA. We are copying input buffer
* into VRFB memory space of desired angle and DSS will
* read image VRFB memory for 0 degree angle
*/
+
pixsize = vout->bpp * vout->vrfb_bpp;
- /*
- * DMA transfer in double index mode
- */
+ dst_icg = ((MAX_PIXELS_PER_LINE * pixsize) -
+ (vout->pix.width * vout->bpp)) + 1;
+
+ xt->src_start = vout->buf_phy_addr[vb->i];
+ xt->dst_start = vout->vrfb_context[vb->i].paddr[0];
+
+ xt->numf = vout->pix.height;
+ xt->frame_size = 1;
+ xt->sgl[0].size = vout->pix.width * vout->bpp;
+ xt->sgl[0].icg = dst_icg;
+
+ xt->dir = DMA_MEM_TO_MEM;
+ xt->src_sgl = false;
+ xt->src_inc = true;
+ xt->dst_sgl = true;
+ xt->dst_inc = true;
+
+ tx = dmadev->device_prep_interleaved_dma(chan, xt, flags);
+ if (tx == NULL) {
+ pr_err("%s: DMA interleaved prep error\n", __func__);
+ return -EINVAL;
+ }
- /* Frame index */
- dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) -
- (vout->pix.width * vout->bpp)) + 1;
-
- /* Source and destination parameters */
- src_element_index = 0;
- src_frame_index = 0;
- dest_element_index = 1;
- /* Number of elements per frame */
- elem_count = vout->pix.width * vout->bpp;
- frame_count = vout->pix.height;
- tx = &vout->vrfb_dma_tx;
- tx->tx_status = 0;
- omap_set_dma_transfer_params(tx->dma_ch, OMAP_DMA_DATA_TYPE_S32,
- (elem_count / 4), frame_count, OMAP_DMA_SYNC_ELEMENT,
- tx->dev_id, 0x0);
- /* src_port required only for OMAP1 */
- omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
- dmabuf, src_element_index, src_frame_index);
- /*set dma source burst mode for VRFB */
- omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
- rotation = calc_rotation(vout);
+ tx->callback = omap_vout_vrfb_dma_tx_callback;
+ tx->callback_param = &vout->vrfb_dma_tx;
+
+ cookie = dmaengine_submit(tx);
+ if (dma_submit_error(cookie)) {
+ pr_err("%s: dmaengine_submit failed (%d)\n", __func__, cookie);
+ return -EINVAL;
+ }
- /* dest_port required only for OMAP1 */
- omap_set_dma_dest_params(tx->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX,
- vout->vrfb_context[vb->i].paddr[0], dest_element_index,
- dest_frame_index);
- /*set dma dest burst mode for VRFB */
- omap_set_dma_dest_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
- omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0);
+ vout->vrfb_dma_tx.tx_status = 0;
+ dma_async_issue_pending(chan);
- omap_start_dma(tx->dma_ch);
- wait_event_interruptible_timeout(tx->wait, tx->tx_status == 1,
+ wait_event_interruptible_timeout(vout->vrfb_dma_tx.wait,
+ vout->vrfb_dma_tx.tx_status == 1,
VRFB_TX_TIMEOUT);
- if (tx->tx_status == 0) {
- omap_stop_dma(tx->dma_ch);
+ status = dma_async_is_tx_complete(chan, cookie, NULL, NULL);
+
+ if (vout->vrfb_dma_tx.tx_status == 0) {
+ pr_err("%s: Timeout while waiting for DMA\n", __func__);
+ dmaengine_terminate_sync(chan);
+ return -EINVAL;
+ } else if (status != DMA_COMPLETE) {
+ pr_err("%s: DMA completion %s status\n", __func__,
+ status == DMA_ERROR ? "error" : "busy");
+ dmaengine_terminate_sync(chan);
return -EINVAL;
}
+
/* Store buffers physical address into an array. Addresses
* from this array will be used to configure DSS */
+ rotation = calc_rotation(vout);
vout->queued_buf_addr[vb->i] = (u8 *)
vout->vrfb_context[vb->i].paddr[rotation];
return 0;
#include <media/v4l2-ctrls.h>
#include <video/omapfb_dss.h>
#include <video/omapvrfb.h>
+#include <linux/dmaengine.h>
#define YUYV_BPP 2
#define RGB565_BPP 2
* for VRFB hidden buffer
*/
struct vid_vrfb_dma {
- int dev_id;
- int dma_ch;
+ struct dma_chan *chan;
+ struct dma_interleaved_template *xt;
+
int req_status;
int tx_status;
wait_queue_head_t wait;
return 0;
err:
- while (--i)
+ while (i--)
clk_disable_unprepare(core->clks[i]);
return ret;
if (val & BLT_INS_IRQ)
seq_puts(s, "IRQ - ");
- seq_puts(s, "\n");
+ seq_putc(s, '\n');
}
static void bdisp_dbg_dump_tty(struct seq_file *s, u32 val)
if (val & BLT_TTY_BIG_END)
seq_puts(s, "BigEndian - ");
- seq_puts(s, "\n");
+ seq_putc(s, '\n');
}
static void bdisp_dbg_dump_xy(struct seq_file *s, u32 val, char *name)
seq_puts(s, "BigEndian - ");
done:
- seq_puts(s, "\n");
+ seq_putc(s, '\n');
}
static void bdisp_dbg_dump_fctl(struct seq_file *s, u32 val)
else if ((val & BLT_FCTL_HV_SCALE) == BLT_FCTL_HV_SAMPLE)
seq_puts(s, "Sample Chroma");
- seq_puts(s, "\n");
+ seq_putc(s, '\n');
}
static void bdisp_dbg_dump_rsf(struct seq_file *s, u32 val, char *name)
seq_printf(s, "V: %d(6.10) / scale~%dx0.1", inc, 1024 * 10 / inc);
done:
- seq_puts(s, "\n");
+ seq_putc(s, '\n');
}
static void bdisp_dbg_dump_rzi(struct seq_file *s, u32 val, char *name)
seq_printf(s, "V: init=%d repeat=%d", val & 0x3FF, (val >> 12) & 7);
done:
- seq_puts(s, "\n");
+ seq_putc(s, '\n');
}
static void bdisp_dbg_dump_ivmx(struct seq_file *s,
seq_printf(s, "IVMX3\t0x%08X\t", c3);
if (!c0 && !c1 && !c2 && !c3) {
- seq_puts(s, "\n");
+ seq_putc(s, '\n');
return;
}
}
}
- if (radio->rds_on)
+ if (radio->rds_on) {
r = core->write(core, WL1273_RDS_DATA_ENB, 1);
- else
+ if (r) {
+ dev_err(dev, "%s: RDS_DATA_ENB ON fails\n",
+ __func__);
+ goto fail;
+ }
+ } else {
r = core->write(core, WL1273_RDS_DATA_ENB, 0);
+ if (r) {
+ dev_err(dev, "%s: RDS_DATA_ENB OFF fails\n",
+ __func__);
+ goto fail;
+ }
+ }
} else {
dev_warn(dev, "%s: Illegal mode.\n", __func__);
}
switch (vco_sel) {
default:
WARN_ON(1);
+ return -EINVAL;
case 0:
if (vco_cal < 8) {
regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0);
status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x7);
divider_val = 2 ;
- Fmax = FmaxBin ;
- Fmin = FminBin ;
}
/* TG_DIV_VAL */
if (err)
goto error;
- pr_info("Remote controller %s initalized\n", ir->name);
+ pr_info("Remote controller %s initialized\n", ir->name);
return 0;
struct lme2510_state *st = d->priv;
u8 all_pids[] = LME_ALL_PIDS;
u8 stream_on[] = LME_ST_ON_W;
- int ret;
u8 rbuff[1];
if (st->pid_off)
- ret = lme2510_usb_talk(d, all_pids, sizeof(all_pids),
- rbuff, sizeof(rbuff));
+ lme2510_usb_talk(d, all_pids, sizeof(all_pids),
+ rbuff, sizeof(rbuff));
/*Restart Stream Command*/
- ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on),
- rbuff, sizeof(rbuff));
- return ret;
+ return lme2510_usb_talk(d, stream_on, sizeof(stream_on),
+ rbuff, sizeof(rbuff));
}
static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out)
USB_CTRL_GET_TIMEOUT);
if (result < 0) {
deb_info("i2c read error (status = %d)\n", result);
- break;
+ goto unlock;
}
if (msg[i].len > sizeof(st->buf)) {
deb_info("buffer too small to fit %d bytes\n",
msg[i].len);
- return -EIO;
+ result = -EIO;
+ goto unlock;
}
memcpy(msg[i].buf, st->buf, msg[i].len);
/* Write request */
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
- mutex_unlock(&d->i2c_mutex);
- return -EINTR;
+ result = -EINTR;
+ goto unlock;
}
st->buf[0] = REQUEST_NEW_I2C_WRITE;
st->buf[1] = msg[i].addr << 1;
if (msg[i].len > sizeof(st->buf) - 4) {
deb_info("i2c message to big: %d\n",
msg[i].len);
- return -EIO;
+ mutex_unlock(&d->usb_mutex);
+ result = -EIO;
+ goto unlock;
}
/* The Actual i2c payload */
}
}
}
+ result = i;
+
+unlock:
mutex_unlock(&d->i2c_mutex);
- return i;
+ return result;
}
/*
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
struct dib0700_state *st = d->priv;
- int i,len;
+ int i, len, result;
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EINTR;
if (msg[i].len > sizeof(st->buf) - 2) {
deb_info("i2c xfer to big: %d\n",
msg[i].len);
- return -EIO;
+ result = -EIO;
+ goto unlock;
}
memcpy(&st->buf[2], msg[i].buf, msg[i].len);
if (len <= 0) {
deb_info("I2C read failed on address 0x%02x\n",
msg[i].addr);
- break;
+ result = -EIO;
+ goto unlock;
}
if (msg[i + 1].len > sizeof(st->buf)) {
deb_info("i2c xfer buffer to small for %d\n",
msg[i].len);
- return -EIO;
+ result = -EIO;
+ goto unlock;
}
memcpy(msg[i + 1].buf, st->buf, msg[i + 1].len);
i++;
} else {
st->buf[0] = REQUEST_I2C_WRITE;
- if (dib0700_ctrl_wr(d, st->buf, msg[i].len + 2) < 0)
- break;
+ result = dib0700_ctrl_wr(d, st->buf, msg[i].len + 2);
+ if (result < 0)
+ goto unlock;
}
}
+ result = i;
+unlock:
mutex_unlock(&d->usb_mutex);
mutex_unlock(&d->i2c_mutex);
- return i;
+ return result;
}
static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
.tuner_gpio = terratec_h5_gpio,
#else
.tuner_type = TUNER_ABSENT,
+#endif
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_400_KHZ,
+ },
+ [EM2884_BOARD_TERRATEC_H6] = {
+ .name = "Terratec Cinergy H6 rev. 2",
+ .has_dvb = 1,
+ .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
+#if 0
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .tuner_addr = 0x41,
+ .dvb_gpio = terratec_h5_digital, /* FIXME: probably wrong */
+ .tuner_gpio = terratec_h5_gpio,
+#else
+ .tuner_type = TUNER_ABSENT,
#endif
.def_i2c_bus = 1,
.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
.driver_info = EM2884_BOARD_TERRATEC_H5 },
{ USB_DEVICE(0x0ccd, 0x10b6), /* H5 Rev. 3 */
.driver_info = EM2884_BOARD_TERRATEC_H5 },
+ { USB_DEVICE(0x0ccd, 0x10b2), /* H6 */
+ .driver_info = EM2884_BOARD_TERRATEC_H6 },
{ USB_DEVICE(0x0ccd, 0x0084),
.driver_info = EM2860_BOARD_TERRATEC_AV350 },
{ USB_DEVICE(0x0ccd, 0x0096),
break;
case EM2884_BOARD_ELGATO_EYETV_HYBRID_2008:
case EM2884_BOARD_CINERGY_HTC_STICK:
+ case EM2884_BOARD_TERRATEC_H6:
terratec_htc_stick_init(dev);
/* attach demodulator */
dev_err(&dev->intf->dev,
"%s: em28xx_i2_eeprom failed! retval [%d]\n",
__func__, retval);
-
- return retval;
}
}
if (err)
goto error;
- dev_info(&dev->intf->dev, "Input extension successfully initalized\n");
+ dev_info(&dev->intf->dev, "Input extension successfully initialized\n");
return 0;
#define EM28178_BOARD_PLEX_PX_BCUD 98
#define EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB 99
#define EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 100
+#define EM2884_BOARD_TERRATEC_H6 101
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
while (true) {
unsigned long flags;
- bool exit_loop = false;
char data;
spin_lock_irqsave(&rain->buf_lock, flags);
- if (rain->buf_len) {
- data = rain->buf[rain->buf_rd_idx];
- rain->buf_len--;
- rain->buf_rd_idx = (rain->buf_rd_idx + 1) & 0xff;
- } else {
- exit_loop = true;
+ if (!rain->buf_len) {
+ spin_unlock_irqrestore(&rain->buf_lock, flags);
+ break;
}
- spin_unlock_irqrestore(&rain->buf_lock, flags);
- if (exit_loop)
- break;
+ data = rain->buf[rain->buf_rd_idx];
+ rain->buf_len--;
+ rain->buf_rd_idx = (rain->buf_rd_idx + 1) & 0xff;
+
+ spin_unlock_irqrestore(&rain->buf_lock, flags);
if (!rain->cmd_started && data != '?')
continue;
/* It seems the i2c bus is controlled with these registers */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include "stk-webcam.h"
#define STK_IIC_BASE (0x0200)
} while (tmpval == 0 && i < MAX_RETRIES);
if (tmpval != STK_IIC_STAT_TX_OK) {
if (tmpval)
- STK_ERROR("stk_sensor_outb failed, status=0x%02x\n",
- tmpval);
+ pr_err("stk_sensor_outb failed, status=0x%02x\n",
+ tmpval);
return 1;
} else
return 0;
} while (tmpval == 0 && i < MAX_RETRIES);
if (tmpval != STK_IIC_STAT_RX_OK) {
if (tmpval)
- STK_ERROR("stk_sensor_inb failed, status=0x%02x\n",
- tmpval);
+ pr_err("stk_sensor_inb failed, status=0x%02x\n",
+ tmpval);
return 1;
}
if (stk_camera_write_reg(dev, STK_IIC_ENABLE, STK_IIC_ENABLE_YES)
|| stk_camera_write_reg(dev, STK_IIC_ADDR, SENSOR_ADDRESS)
|| stk_sensor_outb(dev, REG_COM7, COM7_RESET)) {
- STK_ERROR("Sensor resetting failed\n");
+ pr_err("Sensor resetting failed\n");
return -ENODEV;
}
msleep(10);
/* Read the manufacturer ID: ov = 0x7FA2 */
if (stk_sensor_inb(dev, REG_MIDH, &idh)
|| stk_sensor_inb(dev, REG_MIDL, &idl)) {
- STK_ERROR("Strange error reading sensor ID\n");
+ pr_err("Strange error reading sensor ID\n");
return -ENODEV;
}
if (idh != 0x7f || idl != 0xa2) {
- STK_ERROR("Huh? you don't have a sensor from ovt\n");
+ pr_err("Huh? you don't have a sensor from ovt\n");
return -ENODEV;
}
if (stk_sensor_inb(dev, REG_PID, &idh)
|| stk_sensor_inb(dev, REG_VER, &idl)) {
- STK_ERROR("Could not read sensor model\n");
+ pr_err("Could not read sensor model\n");
return -ENODEV;
}
stk_sensor_write_regvals(dev, ov_initvals);
msleep(10);
- STK_INFO("OmniVision sensor detected, id %02X%02X at address %x\n",
- idh, idl, SENSOR_ADDRESS);
+ pr_info("OmniVision sensor detected, id %02X%02X at address %x\n",
+ idh, idl, SENSOR_ADDRESS);
return 0;
}
case MODE_SXGA: com7 = COM7_FMT_SXGA;
dummylines = 0;
break;
- default: STK_ERROR("Unsupported mode %d\n", dev->vsettings.mode);
+ default:
+ pr_err("Unsupported mode %d\n", dev->vsettings.mode);
return -EFAULT;
}
switch (dev->vsettings.palette) {
com7 |= COM7_PBAYER;
rv = ov_fmt_bayer;
break;
- default: STK_ERROR("Unsupported colorspace\n");
+ default:
+ pr_err("Unsupported colorspace\n");
return -EFAULT;
}
/*FIXME sometimes the sensor go to a bad state
switch (dev->vsettings.mode) {
case MODE_VGA:
if (stk_sensor_set_hw(dev, 302, 1582, 6, 486))
- STK_ERROR("stk_sensor_set_hw failed (VGA)\n");
+ pr_err("stk_sensor_set_hw failed (VGA)\n");
break;
case MODE_SXGA:
case MODE_CIF:
case MODE_QCIF:
/*FIXME These settings seem ignored by the sensor
if (stk_sensor_set_hw(dev, 220, 1500, 10, 1034))
- STK_ERROR("stk_sensor_set_hw failed (SXGA)\n");
+ pr_err("stk_sensor_set_hw failed (SXGA)\n");
*/
break;
}
* GNU General Public License for more details.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
if (!is_present(dev))
return -ENODEV;
if (!is_memallocd(dev) || !is_initialised(dev)) {
- STK_ERROR("FIXME: Buffers are not allocated\n");
+ pr_err("FIXME: Buffers are not allocated\n");
return -EFAULT;
}
ret = usb_set_interface(dev->udev, 0, 5);
if (ret < 0)
- STK_ERROR("usb_set_interface failed !\n");
+ pr_err("usb_set_interface failed !\n");
if (stk_sensor_wakeup(dev))
- STK_ERROR("error awaking the sensor\n");
+ pr_err("error awaking the sensor\n");
stk_camera_read_reg(dev, 0x0116, &value_116);
stk_camera_read_reg(dev, 0x0117, &value_117);
unset_streaming(dev);
if (usb_set_interface(dev->udev, 0, 0))
- STK_ERROR("usb_set_interface failed !\n");
+ pr_err("usb_set_interface failed !\n");
if (stk_sensor_sleep(dev))
- STK_ERROR("error suspending the sensor\n");
+ pr_err("error suspending the sensor\n");
}
return 0;
}
dev = (struct stk_camera *) urb->context;
if (dev == NULL) {
- STK_ERROR("isoc_handler called with NULL device !\n");
+ pr_err("isoc_handler called with NULL device !\n");
return;
}
spin_lock_irqsave(&dev->spinlock, flags);
if (urb->status != -EINPROGRESS && urb->status != 0) {
- STK_ERROR("isoc_handler: urb->status == %d\n", urb->status);
+ pr_err("isoc_handler: urb->status == %d\n", urb->status);
goto resubmit;
}
if (list_empty(&dev->sio_avail)) {
/*FIXME Stop streaming after a while */
- (void) (printk_ratelimit() &&
- STK_ERROR("isoc_handler without available buffer!\n"));
+ pr_err_ratelimited("isoc_handler without available buffer!\n");
goto resubmit;
}
fb = list_first_entry(&dev->sio_avail,
for (i = 0; i < urb->number_of_packets; i++) {
if (urb->iso_frame_desc[i].status != 0) {
if (urb->iso_frame_desc[i].status != -EXDEV)
- STK_ERROR("Frame %d has error %d\n", i,
- urb->iso_frame_desc[i].status);
+ pr_err("Frame %d has error %d\n",
+ i, urb->iso_frame_desc[i].status);
continue;
}
framelen = urb->iso_frame_desc[i].actual_length;
/* This marks a new frame */
if (fb->v4lbuf.bytesused != 0
&& fb->v4lbuf.bytesused != dev->frame_size) {
- (void) (printk_ratelimit() &&
- STK_ERROR("frame %d, bytesused=%d, skipping\n",
- i, fb->v4lbuf.bytesused));
+ pr_err_ratelimited("frame %d, bytesused=%d, skipping\n",
+ i, fb->v4lbuf.bytesused);
fb->v4lbuf.bytesused = 0;
fill = fb->buffer;
} else if (fb->v4lbuf.bytesused == dev->frame_size) {
/* Our buffer is full !!! */
if (framelen + fb->v4lbuf.bytesused > dev->frame_size) {
- (void) (printk_ratelimit() &&
- STK_ERROR("Frame buffer overflow, lost sync\n"));
+ pr_err_ratelimited("Frame buffer overflow, lost sync\n");
/*FIXME Do something here? */
continue;
}
urb->dev = dev->udev;
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret != 0) {
- STK_ERROR("Error (%d) re-submitting urb in stk_isoc_handler.\n",
- ret);
+ pr_err("Error (%d) re-submitting urb in stk_isoc_handler\n",
+ ret);
}
}
udev = dev->udev;
if (dev->isobufs)
- STK_ERROR("isobufs already allocated. Bad\n");
+ pr_err("isobufs already allocated. Bad\n");
else
dev->isobufs = kcalloc(MAX_ISO_BUFS, sizeof(*dev->isobufs),
GFP_KERNEL);
if (dev->isobufs == NULL) {
- STK_ERROR("Unable to allocate iso buffers\n");
+ pr_err("Unable to allocate iso buffers\n");
return -ENOMEM;
}
for (i = 0; i < MAX_ISO_BUFS; i++) {
if (dev->isobufs[i].data == NULL) {
kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
if (kbuf == NULL) {
- STK_ERROR("Failed to allocate iso buffer %d\n",
- i);
+ pr_err("Failed to allocate iso buffer %d\n", i);
goto isobufs_out;
}
dev->isobufs[i].data = kbuf;
} else
- STK_ERROR("isobuf data already allocated\n");
+ pr_err("isobuf data already allocated\n");
if (dev->isobufs[i].urb == NULL) {
urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
if (urb == NULL)
goto isobufs_out;
dev->isobufs[i].urb = urb;
} else {
- STK_ERROR("Killing URB\n");
+ pr_err("Killing URB\n");
usb_kill_urb(dev->isobufs[i].urb);
urb = dev->isobufs[i].urb;
}
{
int i;
if (dev->sio_bufs != NULL)
- STK_ERROR("sio_bufs already allocated\n");
+ pr_err("sio_bufs already allocated\n");
else {
dev->sio_bufs = kzalloc(n_sbufs * sizeof(struct stk_sio_buffer),
GFP_KERNEL);
spin_lock_irqsave(&dev->spinlock, flags);
if (list_empty(&dev->sio_full)) {
spin_unlock_irqrestore(&dev->spinlock, flags);
- STK_ERROR("BUG: No siobufs ready\n");
+ pr_err("BUG: No siobufs ready\n");
return 0;
}
sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list);
stk_sizes[i].m != dev->vsettings.mode; i++)
;
if (i == ARRAY_SIZE(stk_sizes)) {
- STK_ERROR("ERROR: mode invalid\n");
+ pr_err("ERROR: mode invalid\n");
return -EINVAL;
}
pix_format->width = stk_sizes[i].w;
stk_sizes[i].m != dev->vsettings.mode)
i++;
if (i == ARRAY_SIZE(stk_sizes)) {
- STK_ERROR("Something is broken in %s\n", __func__);
+ pr_err("Something is broken in %s\n", __func__);
return -EFAULT;
}
/* This registers controls some timings, not sure of what. */
struct stk_camera *dev = vdev_to_camera(vd);
if (dev->sio_bufs != NULL || dev->isobufs != NULL)
- STK_ERROR("We are leaking memory\n");
+ pr_err("We are leaking memory\n");
usb_put_intf(dev->interface);
kfree(dev);
}
video_set_drvdata(&dev->vdev, dev);
err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1);
if (err)
- STK_ERROR("v4l registration failed\n");
+ pr_err("v4l registration failed\n");
else
- STK_INFO("Syntek USB2.0 Camera is now controlling device %s\n",
- video_device_node_name(&dev->vdev));
+ pr_info("Syntek USB2.0 Camera is now controlling device %s\n",
+ video_device_node_name(&dev->vdev));
return err;
}
dev = kzalloc(sizeof(struct stk_camera), GFP_KERNEL);
if (dev == NULL) {
- STK_ERROR("Out of memory !\n");
+ pr_err("Out of memory !\n");
return -ENOMEM;
}
err = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
}
}
if (!dev->isoc_ep) {
- STK_ERROR("Could not find isoc-in endpoint");
+ pr_err("Could not find isoc-in endpoint\n");
err = -ENODEV;
goto error;
}
wake_up_interruptible(&dev->wait_frame);
- STK_INFO("Syntek USB2.0 Camera release resources device %s\n",
- video_device_node_name(&dev->vdev));
+ pr_info("Syntek USB2.0 Camera release resources device %s\n",
+ video_device_node_name(&dev->vdev));
video_unregister_device(&dev->vdev);
v4l2_ctrl_handler_free(&dev->hdl);
#define ISO_MAX_FRAME_SIZE 3 * 1024
#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
-
-#define PREFIX "stkwebcam: "
-#define STK_INFO(str, args...) printk(KERN_INFO PREFIX str, ##args)
-#define STK_ERROR(str, args...) printk(KERN_ERR PREFIX str, ##args)
-#define STK_WARNING(str, args...) printk(KERN_WARNING PREFIX str, ##args)
-
struct stk_iso_buf {
void *data;
int length;
#define UNSET (-1U)
-#define PREFIX (t->i2c->dev.driver->name)
-
/*
* Driver modprobe parameters
*/
/*
* cxd2099.c: Driver for the CXD2099AR Common Interface Controller
*
- * Copyright (C) 2010-2011 Digital Devices GmbH
+ * Copyright (C) 2010-2013 Digital Devices GmbH
*
*
* This program is free software; you can redistribute it and/or
#include "cxd2099.h"
-#define MAX_BUFFER_SIZE 248
+/* comment this line to deactivate the cxd2099ar buffer mode */
+#define BUFFER_MODE 1
+
+static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount);
struct cxd {
struct dvb_ca_en50221 en;
int mode;
int ready;
int dr;
+ int write_busy;
int slot_stat;
u8 amem[1024];
int cammode;
struct mutex lock;
+
+ u8 rbuf[1028];
+ u8 wbuf[1028];
};
static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr,
}
static int i2c_write(struct i2c_adapter *adapter, u8 adr,
- u8 *data, u8 len)
+ u8 *data, u16 len)
{
struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len};
}
static int i2c_read(struct i2c_adapter *adapter, u8 adr,
- u8 reg, u8 *data, u8 n)
+ u8 reg, u8 *data, u16 n)
{
struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
- .buf = ®, .len = 1},
- {.addr = adr, .flags = I2C_M_RD,
- .buf = data, .len = n} };
+ .buf = ®, .len = 1},
+ {.addr = adr, .flags = I2C_M_RD,
+ .buf = data, .len = n} };
if (i2c_transfer(adapter, msgs, 2) != 2) {
dev_err(&adapter->dev, "error in i2c_read\n");
return 0;
}
-static int read_block(struct cxd *ci, u8 adr, u8 *data, u8 n)
+static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
{
- int status;
+ int status = 0;
- status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
+ if (ci->lastaddress != adr)
+ status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
if (!status) {
ci->lastaddress = adr;
- status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, n);
+
+ while (n) {
+ int len = n;
+
+ if (ci->cfg.max_i2c && (len > ci->cfg.max_i2c))
+ len = ci->cfg.max_i2c;
+ status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, len);
+ if (status)
+ return status;
+ data += len;
+ n -= len;
+ }
}
return status;
}
static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask)
{
- int status;
+ int status = 0;
- status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, reg);
+ if (ci->lastaddress != reg)
+ status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, reg);
if (!status && reg >= 6 && reg <= 8 && mask != 0xff)
status = i2c_read_reg(ci->i2c, ci->cfg.adr, 1, &ci->regs[reg]);
+ ci->lastaddress = reg;
ci->regs[reg] = (ci->regs[reg] & (~mask)) | val;
- if (!status) {
- ci->lastaddress = reg;
+ if (!status)
status = i2c_write_reg(ci->i2c, ci->cfg.adr, 1, ci->regs[reg]);
- }
if (reg == 0x20)
ci->regs[reg] &= 0x7f;
return status;
}
#ifdef BUFFER_MODE
-static int write_block(struct cxd *ci, u8 adr, u8 *data, int n)
+static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
{
- int status;
- u8 buf[256] = {1};
-
- status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
- if (!status) {
- ci->lastaddress = adr;
- memcpy(buf + 1, data, n);
- status = i2c_write(ci->i2c, ci->cfg.adr, buf, n + 1);
+ int status = 0;
+ u8 *buf = ci->wbuf;
+
+ if (ci->lastaddress != adr)
+ status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
+ if (status)
+ return status;
+
+ ci->lastaddress = adr;
+ buf[0] = 1;
+ while (n) {
+ int len = n;
+
+ if (ci->cfg.max_i2c && (len + 1 > ci->cfg.max_i2c))
+ len = ci->cfg.max_i2c - 1;
+ memcpy(buf + 1, data, len);
+ status = i2c_write(ci->i2c, ci->cfg.adr, buf, len + 1);
+ if (status)
+ return status;
+ n -= len;
+ data += len;
}
return status;
}
static void cam_mode(struct cxd *ci, int mode)
{
+ u8 dummy;
+
if (mode == ci->cammode)
return;
write_regm(ci, 0x20, 0x80, 0x80);
break;
case 0x01:
-#ifdef BUFFER_MODE
if (!ci->en.read_data)
return;
+ ci->write_busy = 0;
dev_info(&ci->i2c->dev, "enable cam buffer mode\n");
- /* write_reg(ci, 0x0d, 0x00); */
- /* write_reg(ci, 0x0e, 0x01); */
+ write_reg(ci, 0x0d, 0x00);
+ write_reg(ci, 0x0e, 0x01);
write_regm(ci, 0x08, 0x40, 0x40);
- /* read_reg(ci, 0x12, &dummy); */
+ read_reg(ci, 0x12, &dummy);
write_regm(ci, 0x08, 0x80, 0x80);
-#endif
break;
default:
break;
if (status < 0)
break;
- if (ci->cfg.clock_mode) {
+ if (ci->cfg.clock_mode == 2) {
+ /* bitrate*2^13/ 72000 */
+ u32 reg = ((ci->cfg.bitrate << 13) + 71999) / 72000;
+
if (ci->cfg.polarity) {
status = write_reg(ci, 0x09, 0x6f);
if (status < 0)
if (status < 0)
break;
}
+ status = write_reg(ci, 0x20, 0x08);
+ if (status < 0)
+ break;
+ status = write_reg(ci, 0x21, (reg >> 8) & 0xff);
+ if (status < 0)
+ break;
+ status = write_reg(ci, 0x22, reg & 0xff);
+ if (status < 0)
+ break;
+ } else if (ci->cfg.clock_mode == 1) {
+ if (ci->cfg.polarity) {
+ status = write_reg(ci, 0x09, 0x6f); /* D */
+ if (status < 0)
+ break;
+ } else {
+ status = write_reg(ci, 0x09, 0x6d);
+ if (status < 0)
+ break;
+ }
status = write_reg(ci, 0x20, 0x68);
if (status < 0)
break;
break;
} else {
if (ci->cfg.polarity) {
- status = write_reg(ci, 0x09, 0x4f);
+ status = write_reg(ci, 0x09, 0x4f); /* C */
if (status < 0)
break;
} else {
if (status < 0)
break;
}
-
status = write_reg(ci, 0x20, 0x28);
if (status < 0)
break;
set_mode(ci, 1);
read_pccard(ci, address, &val, 1);
mutex_unlock(&ci->lock);
- /* printk(KERN_INFO "%02x:%02x\n", address,val); */
return val;
}
{
struct cxd *ci = ca->data;
+ if (ci->cammode)
+ read_data(ca, slot, ci->rbuf, 0);
+
mutex_lock(&ci->lock);
cam_mode(ci, 0);
write_reg(ci, 0x00, 0x21);
}
}
mutex_unlock(&ci->lock);
- /* msleep(500); */
return 0;
}
struct cxd *ci = ca->data;
dev_info(&ci->i2c->dev, "%s\n", __func__);
+ if (ci->cammode)
+ read_data(ca, slot, ci->rbuf, 0);
mutex_lock(&ci->lock);
+ write_reg(ci, 0x00, 0x21);
+ write_reg(ci, 0x06, 0x1F);
+ msleep(300);
+
write_regm(ci, 0x09, 0x08, 0x08);
write_regm(ci, 0x20, 0x80, 0x80); /* Reset CAM Mode */
write_regm(ci, 0x06, 0x07, 0x07); /* Clear IO Mode */
+
ci->mode = -1;
+ ci->write_busy = 0;
mutex_unlock(&ci->lock);
return 0;
}
mutex_lock(&ci->lock);
write_regm(ci, 0x09, 0x00, 0x08);
set_mode(ci, 0);
-#ifdef BUFFER_MODE
cam_mode(ci, 1);
-#endif
mutex_unlock(&ci->lock);
return 0;
}
return 0;
write_reg(ci, 0x05, istat);
- if (istat & 0x40) {
+ if (istat & 0x40)
ci->dr = 1;
- dev_info(&ci->i2c->dev, "DR\n");
- }
if (istat & 0x20)
- dev_info(&ci->i2c->dev, "WC\n");
+ ci->write_busy = 0;
if (istat & 2) {
u8 slotstat;
read_reg(ci, 0x01, &slotstat);
if (!(2 & slotstat)) {
if (!ci->slot_stat) {
- ci->slot_stat = DVB_CA_EN50221_POLL_CAM_PRESENT;
+ ci->slot_stat |=
+ DVB_CA_EN50221_POLL_CAM_PRESENT;
write_regm(ci, 0x03, 0x08, 0x08);
}
ci->ready = 0;
}
}
- if (istat & 8 &&
- ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) {
+ if ((istat & 8) &&
+ (ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT)) {
ci->ready = 1;
ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY;
}
return ci->slot_stat;
}
-#ifdef BUFFER_MODE
static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
{
struct cxd *ci = ca->data;
campoll(ci);
mutex_unlock(&ci->lock);
- dev_info(&ci->i2c->dev, "%s\n", __func__);
if (!ci->dr)
return 0;
mutex_lock(&ci->lock);
read_reg(ci, 0x0f, &msb);
read_reg(ci, 0x10, &lsb);
- len = (msb << 8) | lsb;
+ len = ((u16)msb << 8) | lsb;
+ if (len > ecount || len < 2) {
+ /* read it anyway or cxd may hang */
+ read_block(ci, 0x12, ci->rbuf, len);
+ mutex_unlock(&ci->lock);
+ return -EIO;
+ }
read_block(ci, 0x12, ebuf, len);
ci->dr = 0;
mutex_unlock(&ci->lock);
-
return len;
}
+#ifdef BUFFER_MODE
+
static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
{
struct cxd *ci = ca->data;
+ if (ci->write_busy)
+ return -EAGAIN;
mutex_lock(&ci->lock);
- dev_info(&ci->i2c->dev, "%s %d\n", __func__, ecount);
write_reg(ci, 0x0d, ecount >> 8);
write_reg(ci, 0x0e, ecount & 0xff);
write_block(ci, 0x11, ebuf, ecount);
+ ci->write_busy = 1;
mutex_unlock(&ci->lock);
return ecount;
}
struct cxd2099_cfg {
u32 bitrate;
u8 adr;
- u8 polarity:1;
- u8 clock_mode:1;
+ u8 polarity;
+ u8 clock_mode;
+
+ u32 max_i2c;
};
#if defined(CONFIG_DVB_CXD2099) || \