1
0
mirror of https://github.com/DigitalDevices/dddvb.git synced 2023-10-10 13:37:43 +02:00

adapt dvb-core, includes and affected files to mainline 4.14-rc2

This commit is contained in:
Ralph Metzler 2017-09-26 21:18:04 +02:00
parent f84d196a1e
commit 1c22a07eaa
41 changed files with 4770 additions and 2347 deletions

View File

@ -1254,7 +1254,7 @@ static int tuner_attach_stv6110(struct ddb_input *input, int type)
struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900; struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900;
struct stv6110x_config *tunerconf = (input->nr & 1) ? struct stv6110x_config *tunerconf = (input->nr & 1) ?
&stv6110b : &stv6110a; &stv6110b : &stv6110a;
struct stv6110x_devctl *ctl; const struct stv6110x_devctl *ctl;
ctl = dvb_attach(stv6110x_attach, dvb->fe, tunerconf, i2c); ctl = dvb_attach(stv6110x_attach, dvb->fe, tunerconf, i2c);
if (!ctl) { if (!ctl) {
@ -2081,13 +2081,13 @@ static int ddb_port_attach(struct ddb_port *port)
ret = dvb_register_device(port->dvb[0].adap, ret = dvb_register_device(port->dvb[0].adap,
&port->dvb[0].dev, &port->dvb[0].dev,
&dvbdev_ci, (void *)port->output, &dvbdev_ci, (void *)port->output,
DVB_DEVICE_CI); DVB_DEVICE_CI, 1);
break; break;
case DDB_PORT_MOD: case DDB_PORT_MOD:
ret = dvb_register_device(port->dvb[0].adap, ret = dvb_register_device(port->dvb[0].adap,
&port->dvb[0].dev, &port->dvb[0].dev,
&dvbdev_mod, (void *)port->output, &dvbdev_mod, (void *)port->output,
DVB_DEVICE_MOD); DVB_DEVICE_MOD, 1);
break; break;
default: default:
break; break;
@ -2937,7 +2937,7 @@ static int ddb_nsd_attach(struct ddb *dev)
ret = dvb_register_device(&dev->adap[0], ret = dvb_register_device(&dev->adap[0],
&dev->nsd_dev, &dev->nsd_dev,
&dvbdev_nsd, (void *)dev, &dvbdev_nsd, (void *)dev,
DVB_DEVICE_NSD); DVB_DEVICE_NSD, 0);
return ret; return ret;
} }

View File

@ -6,7 +6,7 @@
* Ralph Metzler <rjkm@metzlerbros.de> * Ralph Metzler <rjkm@metzlerbros.de>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify dit under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation. * version 2 only, as published by the Free Software Foundation.
* *
* *

View File

@ -407,7 +407,7 @@ struct ddb_ns {
struct ddb_lnb { struct ddb_lnb {
struct mutex lock; /* lock lnb access */ struct mutex lock; /* lock lnb access */
u32 tone; u32 tone;
fe_sec_voltage_t oldvoltage[4]; enum fe_sec_voltage oldvoltage[4];
u32 voltage[4]; u32 voltage[4];
u32 voltages; u32 voltages;
u32 fmode; u32 fmode;

View File

@ -5,7 +5,7 @@
config DVB_MAX_ADAPTERS config DVB_MAX_ADAPTERS
int "maximum number of DVB/ATSC adapters" int "maximum number of DVB/ATSC adapters"
depends on DVB_CORE depends on DVB_CORE
default 8 default 16
range 1 255 range 1 255
help help
Maximum number of DVB/ATSC adapters. Increasing this number Maximum number of DVB/ATSC adapters. Increasing this number
@ -13,7 +13,7 @@ config DVB_MAX_ADAPTERS
if a much lower number of DVB/ATSC adapters is present. if a much lower number of DVB/ATSC adapters is present.
Only values in the range 4-32 are tested. Only values in the range 4-32 are tested.
If you are unsure about this, use the default value 8 If you are unsure about this, use the default value 16
config DVB_DYNAMIC_MINORS config DVB_DYNAMIC_MINORS
bool "Dynamic DVB minor allocation" bool "Dynamic DVB minor allocation"
@ -27,3 +27,16 @@ config DVB_DYNAMIC_MINORS
will be required to manage the device nodes. will be required to manage the device nodes.
If you are unsure about this, say N here. If you are unsure about this, say N here.
config DVB_DEMUX_SECTION_LOSS_LOG
bool "Enable DVB demux section packet loss log"
depends on DVB_CORE
default n
help
Enable extra log messages meant to detect packet loss
inside the Kernel.
Should not be enabled on normal cases, as logs can
be very verbose.
If you are unsure about this, say N here.

View File

@ -1,6 +1,10 @@
/* /*
* demux.h * demux.h
* *
* The Kernel Digital TV Demux kABI defines a driver-internal interface for
* registering low-level, hardware specific driver to a hardware independent
* demux layer.
*
* Copyright (c) 2002 Convergence GmbH * Copyright (c) 2002 Convergence GmbH
* *
* based on code: * based on code:
@ -17,10 +21,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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 __DEMUX_H #ifndef __DEMUX_H
@ -32,9 +32,9 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/dvb/dmx.h> #include <linux/dvb/dmx.h>
/*--------------------------------------------------------------------------*/ /*
/* Common definitions */ * Common definitions
/*--------------------------------------------------------------------------*/ */
/* /*
* DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter. * DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter.
@ -45,7 +45,8 @@
#endif #endif
/* /*
* DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter. * DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed
* filter.
*/ */
#ifndef DMX_MAX_SECTION_SIZE #ifndef DMX_MAX_SECTION_SIZE
@ -55,52 +56,76 @@
#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188) #define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188)
#endif #endif
/* /*
* enum dmx_success: Success codes for the Demux Callback API. * TS packet reception
*/ */
enum dmx_success { /**
DMX_OK = 0, /* Received Ok */ * enum ts_filter_type - filter type bitmap for dmx_ts_feed.set\(\)
DMX_LENGTH_ERROR, /* Incorrect length */ *
DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */ * @TS_PACKET: Send TS packets (188 bytes) to callback (default).
DMX_CRC_ERROR, /* Incorrect CRC */ * @TS_PAYLOAD_ONLY: In case TS_PACKET is set, only send the TS payload
DMX_FRAME_ERROR, /* Frame alignment error */ * (<=184 bytes per packet) to callback
DMX_FIFO_ERROR, /* Receiver FIFO overrun */ * @TS_DECODER: Send stream to built-in decoder (if present).
DMX_MISSED_ERROR /* Receiver missed packet */ * @TS_DEMUX: In case TS_PACKET is set, send the TS to the demux
* device, not to the dvr device
*/
enum ts_filter_type {
TS_PACKET = 1,
TS_PAYLOAD_ONLY = 2,
TS_DECODER = 4,
TS_DEMUX = 8,
}; };
/*--------------------------------------------------------------------------*/ /**
/* TS packet reception */ * struct dmx_ts_feed - Structure that contains a TS feed filter
/*--------------------------------------------------------------------------*/ *
* @is_filtering: Set to non-zero when filtering in progress
/* TS filter type for set() */ * @parent: pointer to struct dmx_demux
* @priv: pointer to private data of the API client
#define TS_PACKET 1 /* send TS packets (188 bytes) to callback (default) */ * @set: sets the TS filter
#define TS_PAYLOAD_ONLY 2 /* in case TS_PACKET is set, only send the TS * @start_filtering: starts TS filtering
payload (<=184 bytes per packet) to callback */ * @stop_filtering: stops TS filtering
#define TS_DECODER 4 /* send stream to built-in decoder (if present) */ *
#define TS_DEMUX 8 /* in case TS_PACKET is set, send the TS to * A TS feed is typically mapped to a hardware PID filter on the demux chip.
the demux device, not to the dvr device */ * Using this API, the client can set the filtering properties to start/stop
* filtering TS packets on a particular TS feed.
*/
struct dmx_ts_feed { struct dmx_ts_feed {
int is_filtering; /* Set to non-zero when filtering in progress */ int is_filtering;
struct dmx_demux *parent; /* Back-pointer */ struct dmx_demux *parent;
void *priv; /* Pointer to private data of the API client */ void *priv;
int (*set)(struct dmx_ts_feed *feed, int (*set)(struct dmx_ts_feed *feed,
u16 pid, u16 pid,
int type, int type,
enum dmx_ts_pes pes_type, enum dmx_ts_pes pes_type,
size_t circular_buffer_size, ktime_t timeout);
struct timespec timeout);
int (*start_filtering)(struct dmx_ts_feed *feed); int (*start_filtering)(struct dmx_ts_feed *feed);
int (*stop_filtering)(struct dmx_ts_feed *feed); int (*stop_filtering)(struct dmx_ts_feed *feed);
}; };
/*--------------------------------------------------------------------------*/ /*
/* Section reception */ * Section reception
/*--------------------------------------------------------------------------*/ */
/**
* struct dmx_section_filter - Structure that describes a section filter
*
* @filter_value: Contains up to 16 bytes (128 bits) of the TS section header
* that will be matched by the section filter
* @filter_mask: Contains a 16 bytes (128 bits) filter mask with the bits
* specified by @filter_value that will be used on the filter
* match logic.
* @filter_mode: Contains a 16 bytes (128 bits) filter mode.
* @parent: Pointer to struct dmx_section_feed.
* @priv: Pointer to private data of the API client.
*
*
* The @filter_mask controls which bits of @filter_value are compared with
* the section headers/payload. On a binary value of 1 in filter_mask, the
* corresponding bits are compared. The filter only accepts sections that are
* equal to filter_value in all the tested bit positions.
*/
struct dmx_section_filter { struct dmx_section_filter {
u8 filter_value[DMX_MAX_FILTER_SIZE]; u8 filter_value[DMX_MAX_FILTER_SIZE];
u8 filter_mask[DMX_MAX_FILTER_SIZE]; u8 filter_mask[DMX_MAX_FILTER_SIZE];
@ -109,21 +134,48 @@ struct dmx_section_filter {
void *priv; /* Pointer to private data of the API client */ void *priv; /* Pointer to private data of the API client */
}; };
/**
* struct dmx_section_feed - Structure that contains a section feed filter
*
* @is_filtering: Set to non-zero when filtering in progress
* @parent: pointer to struct dmx_demux
* @priv: pointer to private data of the API client
* @check_crc: If non-zero, check the CRC values of filtered sections.
* @set: sets the section filter
* @allocate_filter: This function is used to allocate a section filter on
* the demux. It should only be called when no filtering
* is in progress on this section feed. If a filter cannot
* be allocated, the function fails with -ENOSPC.
* @release_filter: This function releases all the resources of a
* previously allocated section filter. The function
* should not be called while filtering is in progress
* on this section feed. After calling this function,
* the caller should not try to dereference the filter
* pointer.
* @start_filtering: starts section filtering
* @stop_filtering: stops section filtering
*
* A TS feed is typically mapped to a hardware PID filter on the demux chip.
* Using this API, the client can set the filtering properties to start/stop
* filtering TS packets on a particular TS feed.
*/
struct dmx_section_feed { struct dmx_section_feed {
int is_filtering; /* Set to non-zero when filtering in progress */ int is_filtering;
struct dmx_demux* parent; /* Back-pointer */ struct dmx_demux *parent;
void* priv; /* Pointer to private data of the API client */ void *priv;
int check_crc; int check_crc;
/* private: Used internally at dvb_demux.c */
u32 crc_val; u32 crc_val;
u8 *secbuf; u8 *secbuf;
u8 secbuf_base[DMX_MAX_SECFEED_SIZE]; u8 secbuf_base[DMX_MAX_SECFEED_SIZE];
u16 secbufp, seclen, tsfeedp; u16 secbufp, seclen, tsfeedp;
/* public: */
int (*set)(struct dmx_section_feed *feed, int (*set)(struct dmx_section_feed *feed,
u16 pid, u16 pid,
size_t circular_buffer_size,
int check_crc); int check_crc);
int (*allocate_filter)(struct dmx_section_feed *feed, int (*allocate_filter)(struct dmx_section_feed *feed,
struct dmx_section_filter **filter); struct dmx_section_filter **filter);
@ -133,82 +185,375 @@ struct dmx_section_feed {
int (*stop_filtering)(struct dmx_section_feed *feed); int (*stop_filtering)(struct dmx_section_feed *feed);
}; };
/*--------------------------------------------------------------------------*/ /**
/* Callback functions */ * typedef dmx_ts_cb - DVB demux TS filter callback function prototype
/*--------------------------------------------------------------------------*/ *
* @buffer1: Pointer to the start of the filtered TS packets.
* @buffer1_length: Length of the TS data in buffer1.
* @buffer2: Pointer to the tail of the filtered TS packets, or NULL.
* @buffer2_length: Length of the TS data in buffer2.
* @source: Indicates which TS feed is the source of the callback.
*
* This function callback prototype, provided by the client of the demux API,
* is called from the demux code. The function is only called when filtering
* on a TS feed has been enabled using the start_filtering\(\) function at
* the &dmx_demux.
* Any TS packets that match the filter settings are copied to a circular
* buffer. The filtered TS packets are delivered to the client using this
* callback function.
* It is expected that the @buffer1 and @buffer2 callback parameters point to
* addresses within the circular buffer, but other implementations are also
* possible. Note that the called party should not try to free the memory
* the @buffer1 and @buffer2 parameters point to.
*
* When this function is called, the @buffer1 parameter typically points to
* the start of the first undelivered TS packet within a circular buffer.
* The @buffer2 buffer parameter is normally NULL, except when the received
* TS packets have crossed the last address of the circular buffer and
* "wrapped" to the beginning of the buffer. In the latter case the @buffer1
* parameter would contain an address within the circular buffer, while the
* @buffer2 parameter would contain the first address of the circular buffer.
* The number of bytes delivered with this function (i.e. @buffer1_length +
* @buffer2_length) is usually equal to the value of callback_length parameter
* given in the set() function, with one exception: if a timeout occurs before
* receiving callback_length bytes of TS data, any undelivered packets are
* immediately delivered to the client by calling this function. The timeout
* duration is controlled by the set() function in the TS Feed API.
*
* If a TS packet is received with errors that could not be fixed by the
* TS-level forward error correction (FEC), the Transport_error_indicator
* flag of the TS packet header should be set. The TS packet should not be
* discarded, as the error can possibly be corrected by a higher layer
* protocol. If the called party is slow in processing the callback, it
* is possible that the circular buffer eventually fills up. If this happens,
* the demux driver should discard any TS packets received while the buffer
* is full and return -EOVERFLOW.
*
* The type of data returned to the callback can be selected by the
* &dmx_ts_feed.@set function. The type parameter decides if the raw
* TS packet (TS_PACKET) or just the payload (TS_PACKET|TS_PAYLOAD_ONLY)
* should be returned. If additionally the TS_DECODER bit is set the stream
* will also be sent to the hardware MPEG decoder.
*
* Return:
*
* - 0, on success;
*
* - -EOVERFLOW, on buffer overflow.
*/
typedef int (*dmx_ts_cb)(const u8 *buffer1, typedef int (*dmx_ts_cb)(const u8 *buffer1,
size_t buffer1_length, size_t buffer1_length,
const u8 *buffer2, const u8 *buffer2,
size_t buffer2_length, size_t buffer2_length,
struct dmx_ts_feed* source, struct dmx_ts_feed *source);
enum dmx_success success);
/**
* typedef dmx_section_cb - DVB demux TS filter callback function prototype
*
* @buffer1: Pointer to the start of the filtered section, e.g.
* within the circular buffer of the demux driver.
* @buffer1_len: Length of the filtered section data in @buffer1,
* including headers and CRC.
* @buffer2: Pointer to the tail of the filtered section data,
* or NULL. Useful to handle the wrapping of a
* circular buffer.
* @buffer2_len: Length of the filtered section data in @buffer2,
* including headers and CRC.
* @source: Indicates which section feed is the source of the
* callback.
*
* This function callback prototype, provided by the client of the demux API,
* is called from the demux code. The function is only called when
* filtering of sections has been enabled using the function
* &dmx_ts_feed.@start_filtering. When the demux driver has received a
* complete section that matches at least one section filter, the client
* is notified via this callback function. Normally this function is called
* for each received section; however, it is also possible to deliver
* multiple sections with one callback, for example when the system load
* is high. If an error occurs while receiving a section, this
* function should be called with the corresponding error type set in the
* success field, whether or not there is data to deliver. The Section Feed
* implementation should maintain a circular buffer for received sections.
* However, this is not necessary if the Section Feed API is implemented as
* a client of the TS Feed API, because the TS Feed implementation then
* buffers the received data. The size of the circular buffer can be
* configured using the &dmx_ts_feed.@set function in the Section Feed API.
* If there is no room in the circular buffer when a new section is received,
* the section must be discarded. If this happens, the value of the success
* parameter should be DMX_OVERRUN_ERROR on the next callback.
*/
typedef int (*dmx_section_cb)(const u8 *buffer1, typedef int (*dmx_section_cb)(const u8 *buffer1,
size_t buffer1_len, size_t buffer1_len,
const u8 *buffer2, const u8 *buffer2,
size_t buffer2_len, size_t buffer2_len,
struct dmx_section_filter * source, struct dmx_section_filter *source);
enum dmx_success success);
/*--------------------------------------------------------------------------*/ /*
/* DVB Front-End */ * DVB Front-End
/*--------------------------------------------------------------------------*/ */
/**
* enum dmx_frontend_source - Used to identify the type of frontend
*
* @DMX_MEMORY_FE: The source of the demux is memory. It means that
* the MPEG-TS to be filtered comes from userspace,
* via write() syscall.
*
* @DMX_FRONTEND_0: The source of the demux is a frontend connected
* to the demux.
*/
enum dmx_frontend_source { enum dmx_frontend_source {
DMX_MEMORY_FE, DMX_MEMORY_FE,
DMX_FRONTEND_0, DMX_FRONTEND_0,
DMX_FRONTEND_1,
DMX_FRONTEND_2,
DMX_FRONTEND_3,
DMX_STREAM_0, /* external stream input, e.g. LVDS */
DMX_STREAM_1,
DMX_STREAM_2,
DMX_STREAM_3
}; };
/**
* struct dmx_frontend - Structure that lists the frontends associated with
* a demux
*
* @connectivity_list: List of front-ends that can be connected to a
* particular demux;
* @source: Type of the frontend.
*
* FIXME: this structure should likely be replaced soon by some
* media-controller based logic.
*/
struct dmx_frontend { struct dmx_frontend {
struct list_head connectivity_list; /* List of front-ends that can struct list_head connectivity_list;
be connected to a particular
demux */
enum dmx_frontend_source source; enum dmx_frontend_source source;
}; };
/*--------------------------------------------------------------------------*/
/* MPEG-2 TS Demux */
/*--------------------------------------------------------------------------*/
/* /*
* Flags OR'ed in the capabilities field of struct dmx_demux. * MPEG-2 TS Demux
*/ */
#define DMX_TS_FILTERING 1 /**
#define DMX_PES_FILTERING 2 * enum dmx_demux_caps - MPEG-2 TS Demux capabilities bitmap
#define DMX_SECTION_FILTERING 4 *
#define DMX_MEMORY_BASED_FILTERING 8 /* write() available */ * @DMX_TS_FILTERING: set if TS filtering is supported;
#define DMX_CRC_CHECKING 16 * @DMX_SECTION_FILTERING: set if section filtering is supported;
#define DMX_TS_DESCRAMBLING 32 * @DMX_MEMORY_BASED_FILTERING: set if write() available.
*
* Those flags are OR'ed in the &dmx_demux.capabilities field
*/
enum dmx_demux_caps {
DMX_TS_FILTERING = 1,
DMX_SECTION_FILTERING = 4,
DMX_MEMORY_BASED_FILTERING = 8,
};
/* /*
* Demux resource type identifier. * Demux resource type identifier.
*/ */
/* /**
* DMX_FE_ENTRY(): Casts elements in the list of registered * DMX_FE_ENTRY - Casts elements in the list of registered
* front-ends from the generic type struct list_head * front-ends from the generic type struct list_head
* to the type * struct dmx_frontend * to the type * struct dmx_frontend
*. *
* @list: list of struct dmx_frontend
*/ */
#define DMX_FE_ENTRY(list) \
list_entry(list, struct dmx_frontend, connectivity_list)
#define DMX_FE_ENTRY(list) list_entry(list, struct dmx_frontend, connectivity_list) /**
* struct dmx_demux - Structure that contains the demux capabilities and
* callbacks.
*
* @capabilities: Bitfield of capability flags.
*
* @frontend: Front-end connected to the demux
*
* @priv: Pointer to private data of the API client
*
* @open: This function reserves the demux for use by the caller and, if
* necessary, initializes the demux. When the demux is no longer needed,
* the function @close should be called. It should be possible for
* multiple clients to access the demux at the same time. Thus, the
* function implementation should increment the demux usage count when
* @open is called and decrement it when @close is called.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* It returns:
* 0 on success;
* -EUSERS, if maximum usage count was reached;
* -EINVAL, on bad parameter.
*
* @close: This function reserves the demux for use by the caller and, if
* necessary, initializes the demux. When the demux is no longer needed,
* the function @close should be called. It should be possible for
* multiple clients to access the demux at the same time. Thus, the
* function implementation should increment the demux usage count when
* @open is called and decrement it when @close is called.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* It returns:
* 0 on success;
* -ENODEV, if demux was not in use (e. g. no users);
* -EINVAL, on bad parameter.
*
* @write: This function provides the demux driver with a memory buffer
* containing TS packets. Instead of receiving TS packets from the DVB
* front-end, the demux driver software will read packets from memory.
* Any clients of this demux with active TS, PES or Section filters will
* receive filtered data via the Demux callback API (see 0). The function
* returns when all the data in the buffer has been consumed by the demux.
* Demux hardware typically cannot read TS from memory. If this is the
* case, memory-based filtering has to be implemented entirely in software.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @buf function parameter contains a pointer to the TS data in
* kernel-space memory.
* The @count function parameter contains the length of the TS data.
* It returns:
* 0 on success;
* -ERESTARTSYS, if mutex lock was interrupted;
* -EINTR, if a signal handling is pending;
* -ENODEV, if demux was removed;
* -EINVAL, on bad parameter.
*
* @allocate_ts_feed: Allocates a new TS feed, which is used to filter the TS
* packets carrying a certain PID. The TS feed normally corresponds to a
* hardware PID filter on the demux chip.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @feed function parameter contains a pointer to the TS feed API and
* instance data.
* The @callback function parameter contains a pointer to the callback
* function for passing received TS packet.
* It returns:
* 0 on success;
* -ERESTARTSYS, if mutex lock was interrupted;
* -EBUSY, if no more TS feeds is available;
* -EINVAL, on bad parameter.
*
* @release_ts_feed: Releases the resources allocated with @allocate_ts_feed.
* Any filtering in progress on the TS feed should be stopped before
* calling this function.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @feed function parameter contains a pointer to the TS feed API and
* instance data.
* It returns:
* 0 on success;
* -EINVAL on bad parameter.
*
* @allocate_section_feed: Allocates a new section feed, i.e. a demux resource
* for filtering and receiving sections. On platforms with hardware
* support for section filtering, a section feed is directly mapped to
* the demux HW. On other platforms, TS packets are first PID filtered in
* hardware and a hardware section filter then emulated in software. The
* caller obtains an API pointer of type dmx_section_feed_t as an out
* parameter. Using this API the caller can set filtering parameters and
* start receiving sections.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @feed function parameter contains a pointer to the TS feed API and
* instance data.
* The @callback function parameter contains a pointer to the callback
* function for passing received TS packet.
* It returns:
* 0 on success;
* -EBUSY, if no more TS feeds is available;
* -EINVAL, on bad parameter.
*
* @release_section_feed: Releases the resources allocated with
* @allocate_section_feed, including allocated filters. Any filtering in
* progress on the section feed should be stopped before calling this
* function.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @feed function parameter contains a pointer to the TS feed API and
* instance data.
* It returns:
* 0 on success;
* -EINVAL, on bad parameter.
*
* @add_frontend: Registers a connectivity between a demux and a front-end,
* i.e., indicates that the demux can be connected via a call to
* @connect_frontend to use the given front-end as a TS source. The
* client of this function has to allocate dynamic or static memory for
* the frontend structure and initialize its fields before calling this
* function. This function is normally called during the driver
* initialization. The caller must not free the memory of the frontend
* struct before successfully calling @remove_frontend.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @frontend function parameter contains a pointer to the front-end
* instance data.
* It returns:
* 0 on success;
* -EINVAL, on bad parameter.
*
* @remove_frontend: Indicates that the given front-end, registered by a call
* to @add_frontend, can no longer be connected as a TS source by this
* demux. The function should be called when a front-end driver or a demux
* driver is removed from the system. If the front-end is in use, the
* function fails with the return value of -EBUSY. After successfully
* calling this function, the caller can free the memory of the frontend
* struct if it was dynamically allocated before the @add_frontend
* operation.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @frontend function parameter contains a pointer to the front-end
* instance data.
* It returns:
* 0 on success;
* -ENODEV, if the front-end was not found,
* -EINVAL, on bad parameter.
*
* @get_frontends: Provides the APIs of the front-ends that have been
* registered for this demux. Any of the front-ends obtained with this
* call can be used as a parameter for @connect_frontend. The include
* file demux.h contains the macro DMX_FE_ENTRY() for converting an
* element of the generic type struct &list_head * to the type
* struct &dmx_frontend *. The caller must not free the memory of any of
* the elements obtained via this function call.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* It returns a struct list_head pointer to the list of front-end
* interfaces, or NULL in the case of an empty list.
*
* @connect_frontend: Connects the TS output of the front-end to the input of
* the demux. A demux can only be connected to a front-end registered to
* the demux with the function @add_frontend. It may or may not be
* possible to connect multiple demuxes to the same front-end, depending
* on the capabilities of the HW platform. When not used, the front-end
* should be released by calling @disconnect_frontend.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @frontend function parameter contains a pointer to the front-end
* instance data.
* It returns:
* 0 on success;
* -EINVAL, on bad parameter.
*
* @disconnect_frontend: Disconnects the demux and a front-end previously
* connected by a @connect_frontend call.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* It returns:
* 0 on success;
* -EINVAL on bad parameter.
*
* @get_pes_pids: Get the PIDs for DMX_PES_AUDIO0, DMX_PES_VIDEO0,
* DMX_PES_TELETEXT0, DMX_PES_SUBTITLE0 and DMX_PES_PCR0.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @pids function parameter contains an array with five u16 elements
* where the PIDs will be stored.
* It returns:
* 0 on success;
* -EINVAL on bad parameter.
*/
struct dmx_demux { struct dmx_demux {
u32 capabilities; /* Bitfield of capability flags */ enum dmx_demux_caps capabilities;
struct dmx_frontend* frontend; /* Front-end connected to the demux */ struct dmx_frontend *frontend;
void* priv; /* Pointer to private data of the API client */ void *priv;
int (*open)(struct dmx_demux *demux); int (*open)(struct dmx_demux *demux);
int (*close)(struct dmx_demux *demux); int (*close)(struct dmx_demux *demux);
int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count); int (*write)(struct dmx_demux *demux, const char __user *buf,
size_t count);
int (*allocate_ts_feed)(struct dmx_demux *demux, int (*allocate_ts_feed)(struct dmx_demux *demux,
struct dmx_ts_feed **feed, struct dmx_ts_feed **feed,
dmx_ts_cb callback); dmx_ts_cb callback);
@ -230,10 +575,13 @@ struct dmx_demux {
int (*get_pes_pids)(struct dmx_demux *demux, u16 *pids); int (*get_pes_pids)(struct dmx_demux *demux, u16 *pids);
int (*get_caps) (struct dmx_demux* demux, struct dmx_caps *caps); /* private: */
int (*set_source) (struct dmx_demux* demux, const dmx_source_t *src);
/*
* Only used at av7110, to read some data from firmware.
* As this was never documented, we have no clue about what's
* there, and its usage on other drivers aren't encouraged.
*/
int (*get_stc)(struct dmx_demux *demux, unsigned int num, int (*get_stc)(struct dmx_demux *demux, unsigned int num,
u64 *stc, unsigned int *base); u64 *stc, unsigned int *base);
}; };

View File

@ -14,12 +14,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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.
*
*/ */
#define pr_fmt(fmt) "dmxdev: " fmt
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/slab.h> #include <linux/slab.h>
@ -28,7 +26,7 @@
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include "dmxdev.h" #include "dmxdev.h"
static int debug; static int debug;
@ -36,7 +34,11 @@ static int debug;
module_param(debug, int, 0644); module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
#define dprintk if (debug) printk #define dprintk(fmt, arg...) do { \
if (debug) \
printk(KERN_DEBUG pr_fmt("%s: " fmt), \
__func__, ##arg); \
} while (0)
static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf, static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
const u8 *src, size_t len) const u8 *src, size_t len)
@ -50,7 +52,7 @@ static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
free = dvb_ringbuffer_free(buf); free = dvb_ringbuffer_free(buf);
if (len > free) { if (len > free) {
dprintk("dmxdev: buffer overflow\n"); dprintk("buffer overflow\n");
return -EOVERFLOW; return -EOVERFLOW;
} }
@ -126,7 +128,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
struct dmxdev *dmxdev = dvbdev->priv; struct dmxdev *dmxdev = dvbdev->priv;
struct dmx_frontend *front; struct dmx_frontend *front;
dprintk("function : %s\n", __func__); dprintk("%s\n", __func__);
if (mutex_lock_interruptible(&dmxdev->mutex)) if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
@ -145,6 +147,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
if ((file->f_flags & O_ACCMODE) == O_RDONLY) { if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
void *mem; void *mem;
if (!dvbdev->readers) { if (!dvbdev->readers) {
mutex_unlock(&dmxdev->mutex); mutex_unlock(&dmxdev->mutex);
return -EBUSY; return -EBUSY;
@ -196,6 +199,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
dvbdev->readers++; dvbdev->readers++;
if (dmxdev->dvr_buffer.data) { if (dmxdev->dvr_buffer.data) {
void *mem = dmxdev->dvr_buffer.data; void *mem = dmxdev->dvr_buffer.data;
/*memory barrier*/
mb(); mb();
spin_lock_irq(&dmxdev->lock); spin_lock_irq(&dmxdev->lock);
dmxdev->dvr_buffer.data = NULL; dmxdev->dvr_buffer.data = NULL;
@ -206,8 +210,6 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
/* TODO */ /* TODO */
dvbdev->users--; dvbdev->users--;
if (dvbdev->users == 1 && dmxdev->exit == 1) { if (dvbdev->users == 1 && dmxdev->exit == 1) {
fops_put(file->f_op);
file->f_op = NULL;
mutex_unlock(&dmxdev->mutex); mutex_unlock(&dmxdev->mutex);
wake_up(&dvbdev->wait_queue); wake_up(&dvbdev->wait_queue);
} else } else
@ -260,7 +262,7 @@ static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
void *newmem; void *newmem;
void *oldmem; void *oldmem;
dprintk("function : %s\n", __func__); dprintk("%s\n", __func__);
if (buf->size == size) if (buf->size == size)
return 0; return 0;
@ -354,8 +356,7 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len, const u8 *buffer2, size_t buffer2_len,
struct dmx_section_filter *filter, struct dmx_section_filter *filter)
enum dmx_success success)
{ {
struct dmxdev_filter *dmxdevfilter = filter->priv; struct dmxdev_filter *dmxdevfilter = filter->priv;
int ret; int ret;
@ -370,7 +371,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
return 0; return 0;
} }
del_timer(&dmxdevfilter->timer); del_timer(&dmxdevfilter->timer);
dprintk("dmxdev: section callback %*ph\n", 6, buffer1); dprintk("section callback %*ph\n", 6, buffer1);
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
buffer1_len); buffer1_len);
if (ret == buffer1_len) { if (ret == buffer1_len) {
@ -388,8 +389,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len, const u8 *buffer2, size_t buffer2_len,
struct dmx_ts_feed *feed, struct dmx_ts_feed *feed)
enum dmx_success success)
{ {
struct dmxdev_filter *dmxdevfilter = feed->priv; struct dmxdev_filter *dmxdevfilter = feed->priv;
struct dvb_ringbuffer *buffer; struct dvb_ringbuffer *buffer;
@ -560,14 +560,15 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
struct dmxdev_filter *filter, struct dmxdev_filter *filter,
struct dmxdev_feed *feed) struct dmxdev_feed *feed)
{ {
struct timespec timeout = { 0 }; ktime_t timeout;
struct dmx_pes_filter_params *para = &filter->params.pes; struct dmx_pes_filter_params *para = &filter->params.pes;
dmx_output_t otype; enum dmx_output otype;
int ret; int ret;
int ts_type; int ts_type;
enum dmx_ts_pes ts_pes; enum dmx_ts_pes ts_pes;
struct dmx_ts_feed *tsfeed; struct dmx_ts_feed *tsfeed;
timeout = ktime_set(0, 0);
feed->ts = NULL; feed->ts = NULL;
otype = para->output; otype = para->output;
@ -593,7 +594,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
tsfeed = feed->ts; tsfeed = feed->ts;
tsfeed->priv = filter; tsfeed->priv = filter;
ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout); ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, timeout);
if (ret < 0) { if (ret < 0) {
dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
return ret; return ret;
@ -659,15 +660,15 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
secfeed, secfeed,
dvb_dmxdev_section_callback); dvb_dmxdev_section_callback);
if (ret < 0) { if (ret < 0) {
printk("DVB (%s): could not alloc feed\n", pr_err("DVB (%s): could not alloc feed\n",
__func__); __func__);
return ret; return ret;
} }
ret = (*secfeed)->set(*secfeed, para->pid, 32768, ret = (*secfeed)->set(*secfeed, para->pid,
(para->flags & DMX_CHECK_CRC) ? 1 : 0); (para->flags & DMX_CHECK_CRC) ? 1 : 0);
if (ret < 0) { if (ret < 0) {
printk("DVB (%s): could not set feed\n", pr_err("DVB (%s): could not set feed\n",
__func__); __func__);
dvb_dmxdev_feed_restart(filter); dvb_dmxdev_feed_restart(filter);
return ret; return ret;
@ -787,7 +788,7 @@ static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
return 0; return 0;
} }
static inline void invert_mode(dmx_filter_t *filter) static inline void invert_mode(struct dmx_filter *filter)
{ {
int i; int i;
@ -848,7 +849,7 @@ static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
struct dmxdev_filter *dmxdevfilter, struct dmxdev_filter *dmxdevfilter,
struct dmx_sct_filter_params *params) struct dmx_sct_filter_params *params)
{ {
dprintk("function : %s, PID=0x%04x, flags=%02x, timeout=%d\n", dprintk("%s: PID=0x%04x, flags=%02x, timeout=%d\n",
__func__, params->pid, params->flags, params->timeout); __func__, params->pid, params->flags, params->timeout);
dvb_dmxdev_filter_stop(dmxdevfilter); dvb_dmxdev_filter_stop(dmxdevfilter);
@ -874,7 +875,7 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
dvb_dmxdev_filter_stop(dmxdevfilter); dvb_dmxdev_filter_stop(dmxdevfilter);
dvb_dmxdev_filter_reset(dmxdevfilter); dvb_dmxdev_filter_reset(dmxdevfilter);
if ((unsigned)params->pes_type > DMX_PES_OTHER) if ((unsigned int)params->pes_type > DMX_PES_OTHER)
return -EINVAL; return -EINVAL;
dmxdevfilter->type = DMXDEV_TYPE_PES; dmxdevfilter->type = DMXDEV_TYPE_PES;
@ -1025,22 +1026,6 @@ static int dvb_demux_do_ioctl(struct file *file,
dmxdev->demux->get_pes_pids(dmxdev->demux, parg); dmxdev->demux->get_pes_pids(dmxdev->demux, parg);
break; break;
case DMX_GET_CAPS:
if (!dmxdev->demux->get_caps) {
ret = -EINVAL;
break;
}
ret = dmxdev->demux->get_caps(dmxdev->demux, parg);
break;
case DMX_SET_SOURCE:
if (!dmxdev->demux->set_source) {
ret = -EINVAL;
break;
}
ret = dmxdev->demux->set_source(dmxdev->demux, parg);
break;
case DMX_GET_STC: case DMX_GET_STC:
if (!dmxdev->demux->get_stc) { if (!dmxdev->demux->get_stc) {
ret = -EINVAL; ret = -EINVAL;
@ -1089,8 +1074,8 @@ static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
struct dmxdev_filter *dmxdevfilter = file->private_data; struct dmxdev_filter *dmxdevfilter = file->private_data;
unsigned int mask = 0; unsigned int mask = 0;
if (!dmxdevfilter) if ((!dmxdevfilter) || dmxdevfilter->dev->exit)
return -EINVAL; return POLLERR;
poll_wait(file, &dmxdevfilter->buffer.queue, wait); poll_wait(file, &dmxdevfilter->buffer.queue, wait);
@ -1120,8 +1105,6 @@ static int dvb_demux_release(struct inode *inode, struct file *file)
mutex_lock(&dmxdev->mutex); mutex_lock(&dmxdev->mutex);
dmxdev->dvbdev->users--; dmxdev->dvbdev->users--;
if (dmxdev->dvbdev->users == 1 && dmxdev->exit == 1) { if (dmxdev->dvbdev->users == 1 && dmxdev->exit == 1) {
fops_put(file->f_op);
file->f_op = NULL;
mutex_unlock(&dmxdev->mutex); mutex_unlock(&dmxdev->mutex);
wake_up(&dmxdev->dvbdev->wait_queue); wake_up(&dmxdev->dvbdev->wait_queue);
} else } else
@ -1140,10 +1123,13 @@ static const struct file_operations dvb_demux_fops = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static struct dvb_device dvbdev_demux = { static const struct dvb_device dvbdev_demux = {
.priv = NULL, .priv = NULL,
.users = 1, .users = 1,
.writers = 1, .writers = 1,
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
.name = "dvb-demux",
#endif
.fops = &dvb_demux_fops .fops = &dvb_demux_fops
}; };
@ -1183,7 +1169,10 @@ static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
struct dmxdev *dmxdev = dvbdev->priv; struct dmxdev *dmxdev = dvbdev->priv;
unsigned int mask = 0; unsigned int mask = 0;
dprintk("function : %s\n", __func__); dprintk("%s\n", __func__);
if (dmxdev->exit)
return POLLERR;
poll_wait(file, &dmxdev->dvr_buffer.queue, wait); poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
@ -1210,13 +1199,15 @@ static const struct file_operations dvb_dvr_fops = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static struct dvb_device dvbdev_dvr = { static const struct dvb_device dvbdev_dvr = {
.priv = NULL, .priv = NULL,
.readers = 1, .readers = 1,
.users = 1, .users = 1,
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
.name = "dvb-dvr",
#endif
.fops = &dvb_dvr_fops .fops = &dvb_dvr_fops
}; };
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
{ {
int i; int i;
@ -1238,9 +1229,9 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
} }
dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
DVB_DEVICE_DEMUX); DVB_DEVICE_DEMUX, dmxdev->filternum);
dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
dmxdev, DVB_DEVICE_DVR); dmxdev, DVB_DEVICE_DVR, dmxdev->filternum);
dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192); dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);

View File

@ -14,10 +14,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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 _DMXDEV_H_ #ifndef _DMXDEV_H_

File diff suppressed because it is too large Load Diff

View File

@ -12,10 +12,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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 _DVB_CA_EN50221_H_ #ifndef _DVB_CA_EN50221_H_
@ -37,104 +33,110 @@
#define DVB_CA_EN50221_CAMCHANGE_REMOVED 0 #define DVB_CA_EN50221_CAMCHANGE_REMOVED 0
#define DVB_CA_EN50221_CAMCHANGE_INSERTED 1 #define DVB_CA_EN50221_CAMCHANGE_INSERTED 1
/**
* struct dvb_ca_en50221- Structure describing a CA interface
/* Structure describing a CA interface */ *
struct dvb_ca_en50221 { * @owner: the module owning this structure
* @read_attribute_mem: function for reading attribute memory on the CAM
/* the module owning this structure */ * @write_attribute_mem: function for writing attribute memory on the CAM
struct module* owner; * @read_cam_control: function for reading the control interface on the CAM
* @write_cam_control: function for reading the control interface on the CAM
/* NOTE: the read_*, write_* and poll_slot_status functions will be * @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
* @poll_slot_status: function to poll slot status. Only necessary if
* DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set.
* @data: private data, used by caller.
* @private: Opaque data used by the dvb_ca core. Do not modify!
*
* NOTE: the read_*, write_* and poll_slot_status functions will be
* called for different slots concurrently and need to use locks where * called for different slots concurrently and need to use locks where
* and if appropriate. There will be no concurrent access to one slot. * and if appropriate. There will be no concurrent access to one slot.
*/ */
struct dvb_ca_en50221 {
struct module *owner;
/* functions for accessing attribute memory on the CAM */ int (*read_attribute_mem)(struct dvb_ca_en50221 *ca,
int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address); int slot, int address);
int (*write_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address, u8 value); int (*write_attribute_mem)(struct dvb_ca_en50221 *ca,
int slot, int address, u8 value);
/* functions for accessing the control interface on the CAM */ int (*read_cam_control)(struct dvb_ca_en50221 *ca,
int (*read_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address); int slot, u8 address);
int (*write_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value); int (*write_cam_control)(struct dvb_ca_en50221 *ca,
int slot, u8 address, u8 value);
/* functions for readin/writing data */ int (*read_data)(struct dvb_ca_en50221 *ca,
int (*read_data)(struct dvb_ca_en50221* ca, int slot, u8 *ebuf, int ecount); int slot, u8 *ebuf, int ecount);
int (*write_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);
/* Functions for controlling slots */
int (*slot_reset)(struct dvb_ca_en50221 *ca, int slot); int (*slot_reset)(struct dvb_ca_en50221 *ca, int slot);
int (*slot_shutdown)(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); int (*slot_ts_enable)(struct dvb_ca_en50221 *ca, int slot);
/*
* Poll slot status.
* Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set
*/
int (*poll_slot_status)(struct dvb_ca_en50221 *ca, int slot, int open); int (*poll_slot_status)(struct dvb_ca_en50221 *ca, int slot, int open);
/* private data, used by caller */
void *data; void *data;
/* Opaque data used by the dvb_ca core. Do not modify! */
void *private; void *private;
}; };
/*
* Functions for reporting IRQ events
/* ******************************************************************************** */
/* Functions for reporting IRQ events */
/**
* A CAMCHANGE IRQ has occurred.
*
* @param ca CA instance.
* @param slot Slot concerned.
* @param change_type One of the DVB_CA_CAMCHANGE_* values
*/ */
void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type);
/** /**
* A CAMREADY IRQ has occurred. * dvb_ca_en50221_camchange_irq - A CAMCHANGE IRQ has occurred.
* *
* @param ca CA instance. * @pubca: CA instance.
* @param slot Slot concerned. * @slot: Slot concerned.
* @change_type: One of the DVB_CA_CAMCHANGE_* values
*/
void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot,
int change_type);
/**
* dvb_ca_en50221_camready_irq - A CAMREADY IRQ has occurred.
*
* @pubca: CA instance.
* @slot: Slot concerned.
*/ */
void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot); void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot);
/** /**
* An FR or a DA IRQ has occurred. * dvb_ca_en50221_frda_irq - An FR or a DA IRQ has occurred.
* *
* @param ca CA instance. * @ca: CA instance.
* @param slot Slot concerned. * @slot: Slot concerned.
*/ */
void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *ca, int slot); void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *ca, int slot);
/*
* Initialisation/shutdown functions
/* ******************************************************************************** */ */
/* Initialisation/shutdown functions */
/** /**
* Initialise a new DVB CA device. * dvb_ca_en50221_init - Initialise a new DVB CA device.
* *
* @param dvb_adapter DVB adapter to attach the new CA device to. * @dvb_adapter: DVB adapter to attach the new CA device to.
* @param ca The dvb_ca instance. * @ca: The dvb_ca instance.
* @param flags Flags describing the CA device (DVB_CA_EN50221_FLAG_*). * @flags: Flags describing the CA device (DVB_CA_EN50221_FLAG_*).
* @param slot_count Number of slots supported. * @slot_count: Number of slots supported.
* *
* @return 0 on success, nonzero on failure * @return 0 on success, nonzero on failure
*/ */
extern int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* ca, int flags, int slot_count); int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
struct dvb_ca_en50221 *ca, int flags,
int slot_count);
/** /**
* Release a DVB CA device. * dvb_ca_en50221_release - Release a DVB CA device.
* *
* @param ca The associated dvb_ca instance. * @ca: The associated dvb_ca instance.
*/ */
extern void dvb_ca_en50221_release(struct dvb_ca_en50221* ca); void dvb_ca_en50221_release(struct dvb_ca_en50221 *ca);
#endif #endif

View File

@ -15,12 +15,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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.
*
*/ */
#define pr_fmt(fmt) "dvb_demux: " fmt
#include <linux/version.h> #include <linux/version.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0))
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
@ -34,16 +32,18 @@
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "dvb_demux.h" #include "dvb_demux.h"
#define NOBUFS
/* #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog static inline s64 ktime_ms_delta(const ktime_t later, const ktime_t earlier)
*/ {
// #define DVB_DEMUX_SECTION_LOSS_LOG return ktime_to_ms(ktime_sub(later, earlier));
}
#endif
static int dvb_demux_tscheck; static int dvb_demux_tscheck;
module_param(dvb_demux_tscheck, int, 0644); module_param(dvb_demux_tscheck, int, 0644);
@ -60,9 +60,12 @@ module_param(dvb_demux_feed_err_pkts, int, 0644);
MODULE_PARM_DESC(dvb_demux_feed_err_pkts, MODULE_PARM_DESC(dvb_demux_feed_err_pkts,
"when set to 0, drop packets with the TEI bit set (1 by default)"); "when set to 0, drop packets with the TEI bit set (1 by default)");
#define dprintk(fmt, arg...) \
printk(KERN_DEBUG pr_fmt("%s: " fmt), __func__, ##arg)
#define dprintk_tscheck(x...) do { \ #define dprintk_tscheck(x...) do { \
if (dvb_demux_tscheck && printk_ratelimit()) \ if (dvb_demux_tscheck && printk_ratelimit()) \
printk(x); \ dprintk(x); \
} while (0) } while (0)
/****************************************************************************** /******************************************************************************
@ -114,28 +117,30 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
{ {
int count = payload(buf); int count = payload(buf);
int p; int p;
//int ccok; #ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
//u8 cc; int ccok;
u8 cc;
#endif
if (count == 0) if (count == 0)
return -1; return -1;
p = 188 - count; p = 188 - count;
/* #ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
cc = buf[3] & 0x0f; cc = buf[3] & 0x0f;
ccok = ((feed->cc + 1) & 0x0f) == cc; ccok = ((feed->cc + 1) & 0x0f) == cc;
feed->cc = cc; feed->cc = cc;
if (!ccok) if (!ccok)
printk("missed packet!\n"); dprintk("missed packet!\n");
*/ #endif
if (buf[1] & 0x40) // PUSI ? if (buf[1] & 0x40) // PUSI ?
feed->peslen = 0xfffa; feed->peslen = 0xfffa;
feed->peslen += count; feed->peslen += count;
return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK); return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts);
} }
static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed, static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
@ -157,7 +162,7 @@ static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
return 0; return 0;
return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen, return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen,
NULL, 0, &f->filter, DMX_OK); NULL, 0, &f->filter);
} }
static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed) static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
@ -194,7 +199,7 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
{ {
struct dmx_section_feed *sec = &feed->feed.sec; struct dmx_section_feed *sec = &feed->feed.sec;
#ifdef DVB_DEMUX_SECTION_LOSS_LOG #ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
if (sec->secbufp < sec->tsfeedp) { if (sec->secbufp < sec->tsfeedp) {
int i, n = sec->tsfeedp - sec->secbufp; int i, n = sec->tsfeedp - sec->secbufp;
@ -204,12 +209,12 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
* but just first and last. * but just first and last.
*/ */
if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) { if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) {
printk("dvb_demux.c section ts padding loss: %d/%d\n", dprintk("dvb_demux.c section ts padding loss: %d/%d\n",
n, sec->tsfeedp); n, sec->tsfeedp);
printk("dvb_demux.c pad data:"); dprintk("dvb_demux.c pad data:");
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
printk(" %02x", sec->secbuf[i]); pr_cont(" %02x", sec->secbuf[i]);
printk("\n"); pr_cont("\n");
} }
} }
#endif #endif
@ -247,8 +252,8 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
return 0; return 0;
if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) { if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
#ifdef DVB_DEMUX_SECTION_LOSS_LOG #ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
printk("dvb_demux.c section buffer full loss: %d/%d\n", dprintk("dvb_demux.c section buffer full loss: %d/%d\n",
sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
DMX_MAX_SECFEED_SIZE); DMX_MAX_SECFEED_SIZE);
#endif #endif
@ -281,9 +286,9 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
/* dump [secbuf .. secbuf+seclen) */ /* dump [secbuf .. secbuf+seclen) */
if (feed->pusi_seen) if (feed->pusi_seen)
dvb_dmx_swfilter_section_feed(feed); dvb_dmx_swfilter_section_feed(feed);
#ifdef DVB_DEMUX_SECTION_LOSS_LOG #ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
else else
printk("dvb_demux.c pusi not seen, discarding section data\n"); dprintk("dvb_demux.c pusi not seen, discarding section data\n");
#endif #endif
sec->secbufp += seclen; /* secbufp and secbuf moving together is */ sec->secbufp += seclen; /* secbufp and secbuf moving together is */
sec->secbuf += seclen; /* redundant but saves pointer arithmetic */ sec->secbuf += seclen; /* redundant but saves pointer arithmetic */
@ -317,8 +322,8 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
} }
if (!ccok || dc_i) { if (!ccok || dc_i) {
#ifdef DVB_DEMUX_SECTION_LOSS_LOG #ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
printk("dvb_demux.c discontinuity detected %d bytes lost\n", dprintk("dvb_demux.c discontinuity detected %d bytes lost\n",
count); count);
/* /*
* those bytes under sume circumstances will again be reported * those bytes under sume circumstances will again be reported
@ -349,9 +354,10 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
dvb_dmx_swfilter_section_copy_dump(feed, after, dvb_dmx_swfilter_section_copy_dump(feed, after,
after_len); after_len);
} }
#ifdef DVB_DEMUX_SECTION_LOSS_LOG #ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
else if (count > 0) else if (count > 0)
printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count); dprintk("dvb_demux.c PUSI=1 but %d bytes lost\n",
count);
#endif #endif
} else { } else {
/* PUSI=0 (is not set), no section boundary */ /* PUSI=0 (is not set), no section boundary */
@ -372,8 +378,7 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
if (feed->ts_type & TS_PAYLOAD_ONLY) if (feed->ts_type & TS_PAYLOAD_ONLY)
dvb_dmx_swfilter_payload(feed, buf); dvb_dmx_swfilter_payload(feed, buf);
else else
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts);
DMX_OK);
} }
if (feed->ts_type & TS_DECODER) if (feed->ts_type & TS_DECODER)
if (feed->demux->write_to_decoder) if (feed->demux->write_to_decoder)
@ -404,29 +409,24 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
int dvr_done = 0; int dvr_done = 0;
if (dvb_demux_speedcheck) { if (dvb_demux_speedcheck) {
struct timespec cur_time, delta_time; ktime_t cur_time;
u64 speed_bytes, speed_timedelta; u64 speed_bytes, speed_timedelta;
demux->speed_pkts_cnt++; demux->speed_pkts_cnt++;
/* show speed every SPEED_PKTS_INTERVAL packets */ /* show speed every SPEED_PKTS_INTERVAL packets */
if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) { if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) {
cur_time = current_kernel_time(); cur_time = ktime_get();
if (demux->speed_last_time.tv_sec != 0 && if (ktime_to_ns(demux->speed_last_time) != 0) {
demux->speed_last_time.tv_nsec != 0) {
delta_time = timespec_sub(cur_time,
demux->speed_last_time);
speed_bytes = (u64)demux->speed_pkts_cnt speed_bytes = (u64)demux->speed_pkts_cnt
* 188 * 8; * 188 * 8;
/* convert to 1024 basis */ /* convert to 1024 basis */
speed_bytes = 1000 * div64_u64(speed_bytes, speed_bytes = 1000 * div64_u64(speed_bytes,
1024); 1024);
speed_timedelta = speed_timedelta = ktime_ms_delta(cur_time,
(u64)timespec_to_ns(&delta_time); demux->speed_last_time);
speed_timedelta = div64_u64(speed_timedelta, dprintk("TS speed %llu Kbits/sec \n",
1000000); /* nsec -> usec */
printk(KERN_INFO "TS speed %llu Kbits/sec \n",
div64_u64(speed_bytes, div64_u64(speed_bytes,
speed_timedelta)); speed_timedelta));
} }
@ -437,10 +437,9 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
} }
if (buf[1] & 0x80) { if (buf[1] & 0x80) {
dprintk_tscheck("TEI detected. " dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n",
"PID=0x%x data1=0x%x\n",
pid, buf[1]); pid, buf[1]);
/* data in this packet cant be trusted - drop it unless /* data in this packet can't be trusted - drop it unless
* module option dvb_demux_feed_err_pkts is set */ * module option dvb_demux_feed_err_pkts is set */
if (!dvb_demux_feed_err_pkts) if (!dvb_demux_feed_err_pkts)
return; return;
@ -474,14 +473,16 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
if (feed->pid == pid) if (feed->pid == pid)
dvb_dmx_swfilter_packet_type(feed, buf); dvb_dmx_swfilter_packet_type(feed, buf);
else if (feed->pid == 0x2000) else if (feed->pid == 0x2000)
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK); feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts);
} }
} }
void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
size_t count) size_t count)
{ {
spin_lock(&demux->lock); unsigned long flags;
spin_lock_irqsave(&demux->lock, flags);
while (count--) { while (count--) {
if (buf[0] == 0x47) if (buf[0] == 0x47)
@ -489,7 +490,7 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
buf += 188; buf += 188;
} }
spin_unlock(&demux->lock); spin_unlock_irqrestore(&demux->lock, flags);
} }
EXPORT_SYMBOL(dvb_dmx_swfilter_packets); EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
@ -524,8 +525,9 @@ static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
{ {
int p = 0, i, j; int p = 0, i, j;
const u8 *q; const u8 *q;
unsigned long flags;
spin_lock(&demux->lock); spin_lock_irqsave(&demux->lock, flags);
if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */ if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
i = demux->tsbufp; i = demux->tsbufp;
@ -569,7 +571,7 @@ static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
} }
bailout: bailout:
spin_unlock(&demux->lock); spin_unlock_irqrestore(&demux->lock, flags);
} }
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
@ -586,11 +588,13 @@ EXPORT_SYMBOL(dvb_dmx_swfilter_204);
void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count) void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
{ {
spin_lock(&demux->lock); unsigned long flags;
demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, DMX_OK); spin_lock_irqsave(&demux->lock, flags);
spin_unlock(&demux->lock); demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts);
spin_unlock_irqrestore(&demux->lock, flags);
} }
EXPORT_SYMBOL(dvb_dmx_swfilter_raw); EXPORT_SYMBOL(dvb_dmx_swfilter_raw);
@ -641,7 +645,7 @@ static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
{ {
spin_lock_irq(&feed->demux->lock); spin_lock_irq(&feed->demux->lock);
if (dvb_demux_feed_find(feed)) { if (dvb_demux_feed_find(feed)) {
printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n", pr_err("%s: feed already in list (type=%x state=%x pid=%x)\n",
__func__, feed->type, feed->state, feed->pid); __func__, feed->type, feed->state, feed->pid);
goto out; goto out;
} }
@ -655,7 +659,7 @@ static void dvb_demux_feed_del(struct dvb_demux_feed *feed)
{ {
spin_lock_irq(&feed->demux->lock); spin_lock_irq(&feed->demux->lock);
if (!(dvb_demux_feed_find(feed))) { if (!(dvb_demux_feed_find(feed))) {
printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n", pr_err("%s: feed not in list (type=%x state=%x pid=%x)\n",
__func__, feed->type, feed->state, feed->pid); __func__, feed->type, feed->state, feed->pid);
goto out; goto out;
} }
@ -666,8 +670,7 @@ out:
} }
static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
enum dmx_ts_pes pes_type, enum dmx_ts_pes pes_type, ktime_t timeout)
size_t circular_buffer_size, struct timespec timeout)
{ {
struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
struct dvb_demux *demux = feed->demux; struct dvb_demux *demux = feed->demux;
@ -697,23 +700,10 @@ static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
dvb_demux_feed_add(feed); dvb_demux_feed_add(feed);
feed->pid = pid; feed->pid = pid;
feed->buffer_size = circular_buffer_size;
feed->timeout = timeout; feed->timeout = timeout;
feed->ts_type = ts_type; feed->ts_type = ts_type;
feed->pes_type = pes_type; feed->pes_type = pes_type;
if (feed->buffer_size) {
#ifdef NOBUFS
feed->buffer = NULL;
#else
feed->buffer = vmalloc(feed->buffer_size);
if (!feed->buffer) {
mutex_unlock(&demux->mutex);
return -ENOMEM;
}
#endif
}
feed->state = DMX_STATE_READY; feed->state = DMX_STATE_READY;
mutex_unlock(&demux->mutex); mutex_unlock(&demux->mutex);
@ -802,7 +792,6 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
feed->demux = demux; feed->demux = demux;
feed->pid = 0xffff; feed->pid = 0xffff;
feed->peslen = 0xfffa; feed->peslen = 0xfffa;
feed->buffer = NULL;
(*ts_feed) = &feed->feed.ts; (*ts_feed) = &feed->feed.ts;
(*ts_feed)->parent = dmx; (*ts_feed)->parent = dmx;
@ -839,10 +828,6 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,
mutex_unlock(&demux->mutex); mutex_unlock(&demux->mutex);
return -EINVAL; return -EINVAL;
} }
#ifndef NOBUFS
vfree(feed->buffer);
feed->buffer = NULL;
#endif
feed->state = DMX_STATE_FREE; feed->state = DMX_STATE_FREE;
feed->filter->state = DMX_STATE_FREE; feed->filter->state = DMX_STATE_FREE;
@ -894,8 +879,7 @@ static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed,
} }
static int dmx_section_feed_set(struct dmx_section_feed *feed, static int dmx_section_feed_set(struct dmx_section_feed *feed,
u16 pid, size_t circular_buffer_size, u16 pid, int check_crc)
int check_crc)
{ {
struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
@ -909,19 +893,8 @@ static int dmx_section_feed_set(struct dmx_section_feed *feed,
dvb_demux_feed_add(dvbdmxfeed); dvb_demux_feed_add(dvbdmxfeed);
dvbdmxfeed->pid = pid; dvbdmxfeed->pid = pid;
dvbdmxfeed->buffer_size = circular_buffer_size;
dvbdmxfeed->feed.sec.check_crc = check_crc; dvbdmxfeed->feed.sec.check_crc = check_crc;
#ifdef NOBUFS
dvbdmxfeed->buffer = NULL;
#else
dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size);
if (!dvbdmxfeed->buffer) {
mutex_unlock(&dvbdmx->mutex);
return -ENOMEM;
}
#endif
dvbdmxfeed->state = DMX_STATE_READY; dvbdmxfeed->state = DMX_STATE_READY;
mutex_unlock(&dvbdmx->mutex); mutex_unlock(&dvbdmx->mutex);
return 0; return 0;
@ -1032,8 +1005,13 @@ static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
return -EINVAL; return -EINVAL;
} }
if (feed->is_filtering) if (feed->is_filtering) {
/* release dvbdmx->mutex as far as it is
acquired by stop_filtering() itself */
mutex_unlock(&dvbdmx->mutex);
feed->stop_filtering(feed); feed->stop_filtering(feed);
mutex_lock(&dvbdmx->mutex);
}
spin_lock_irq(&dvbdmx->lock); spin_lock_irq(&dvbdmx->lock);
f = dvbdmxfeed->filter; f = dvbdmxfeed->filter;
@ -1075,7 +1053,6 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0; dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
dvbdmxfeed->feed.sec.tsfeedp = 0; dvbdmxfeed->feed.sec.tsfeedp = 0;
dvbdmxfeed->filter = NULL; dvbdmxfeed->filter = NULL;
dvbdmxfeed->buffer = NULL;
(*feed) = &dvbdmxfeed->feed.sec; (*feed) = &dvbdmxfeed->feed.sec;
(*feed)->is_filtering = 0; (*feed)->is_filtering = 0;
@ -1104,10 +1081,6 @@ static int dvbdmx_release_section_feed(struct dmx_demux *demux,
mutex_unlock(&dvbdmx->mutex); mutex_unlock(&dvbdmx->mutex);
return -EINVAL; return -EINVAL;
} }
#ifndef NOBUFS
vfree(dvbdmxfeed->buffer);
dvbdmxfeed->buffer = NULL;
#endif
dvbdmxfeed->state = DMX_STATE_FREE; dvbdmxfeed->state = DMX_STATE_FREE;
dvb_demux_feed_del(dvbdmxfeed); dvb_demux_feed_del(dvbdmxfeed);
@ -1269,7 +1242,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
dvbdemux->cnt_storage = vmalloc(MAX_PID + 1); dvbdemux->cnt_storage = vmalloc(MAX_PID + 1);
if (!dvbdemux->cnt_storage) if (!dvbdemux->cnt_storage)
printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n"); pr_warn("Couldn't allocate memory for TS/TEI check. Disabling it\n");
INIT_LIST_HEAD(&dvbdemux->frontend_list); INIT_LIST_HEAD(&dvbdemux->frontend_list);

View File

@ -14,10 +14,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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 _DVB_DEMUX_H_ #ifndef _DVB_DEMUX_H_
@ -80,10 +76,8 @@ struct dvb_demux_feed {
int type; int type;
int state; int state;
u16 pid; u16 pid;
u8 *buffer;
int buffer_size;
struct timespec timeout; ktime_t timeout;
struct dvb_demux_filter *filter; struct dvb_demux_filter *filter;
int ts_type; int ts_type;
@ -134,7 +128,7 @@ struct dvb_demux {
uint8_t *cnt_storage; /* for TS continuity check */ uint8_t *cnt_storage; /* for TS continuity check */
struct timespec speed_last_time; /* for TS speed check */ ktime_t speed_last_time; /* for TS speed check */
uint32_t speed_pkts_cnt; /* for TS speed check */ uint32_t speed_pkts_cnt; /* for TS speed check */
}; };

View File

@ -18,19 +18,23 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* * To obtain the license, point your browser to
* You should have received a copy of the GNU General Public License * http://www.gnu.org/copyleft/gpl.html
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*/ */
/* Enables DVBv3 compatibility bits at the headers */ /* Enables DVBv3 compatibility bits at the headers */
#define __DVB_CORE__ #define __DVB_CORE__
#define pr_fmt(fmt) "dvb_frontend: " fmt
#include <linux/string.h> #include <linux/string.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0))
#include <linux/sched/signal.h>
#else
#include <linux/sched.h> #include <linux/sched.h>
#endif
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/poll.h> #include <linux/poll.h>
@ -40,6 +44,7 @@
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/ktime.h>
#include <asm/processor.h> #include <asm/processor.h>
#include "dvb_frontend.h" #include "dvb_frontend.h"
@ -66,6 +71,9 @@ MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volt
module_param(dvb_mfe_wait_time, int, 0644); module_param(dvb_mfe_wait_time, int, 0644);
MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)"); MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)");
#define dprintk(fmt, arg...) \
printk(KERN_DEBUG pr_fmt("%s: " fmt), __func__, ##arg)
#define FESTATE_IDLE 1 #define FESTATE_IDLE 1
#define FESTATE_RETUNE 2 #define FESTATE_RETUNE 2
#define FESTATE_TUNING_FAST 4 #define FESTATE_TUNING_FAST 4
@ -80,7 +88,6 @@ MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open(
#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW) #define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW) #define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
#define FE_ALGO_HW 1
/* /*
* FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling. * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
* FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune. * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
@ -96,14 +103,9 @@ MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open(
* FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again. * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
*/ */
#define DVB_FE_NO_EXIT 0
#define DVB_FE_NORMAL_EXIT 1
#define DVB_FE_DEVICE_REMOVED 2
static DEFINE_MUTEX(frontend_mutex); static DEFINE_MUTEX(frontend_mutex);
struct dvb_frontend_private { struct dvb_frontend_private {
/* thread/frontend values */ /* thread/frontend values */
struct dvb_device *dvbdev; struct dvb_device *dvbdev;
struct dvb_frontend_parameters parameters_out; struct dvb_frontend_parameters parameters_out;
@ -113,9 +115,8 @@ struct dvb_frontend_private {
wait_queue_head_t wait_queue; wait_queue_head_t wait_queue;
struct task_struct *thread; struct task_struct *thread;
unsigned long release_jiffies; unsigned long release_jiffies;
unsigned int exit;
unsigned int wakeup; unsigned int wakeup;
fe_status_t status; enum fe_status status;
unsigned long tune_mode_flags; unsigned long tune_mode_flags;
unsigned int delay; unsigned int delay;
unsigned int reinitialise; unsigned int reinitialise;
@ -136,12 +137,45 @@ struct dvb_frontend_private {
int quality; int quality;
unsigned int check_wrapped; unsigned int check_wrapped;
enum dvbfe_search algo_status; enum dvbfe_search algo_status;
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
struct media_pipeline pipe;
#endif
}; };
static void dvb_frontend_invoke_release(struct dvb_frontend *fe,
void (*release)(struct dvb_frontend *fe));
static void dvb_frontend_free(struct kref *ref)
{
struct dvb_frontend *fe =
container_of(ref, struct dvb_frontend, refcount);
struct dvb_frontend_private *fepriv = fe->frontend_priv;
dvb_free_device(fepriv->dvbdev);
dvb_frontend_invoke_release(fe, fe->ops.release);
kfree(fepriv);
}
static void dvb_frontend_put(struct dvb_frontend *fe)
{
kref_put(&fe->refcount, dvb_frontend_free);
}
static void dvb_frontend_get(struct dvb_frontend *fe)
{
kref_get(&fe->refcount);
}
static void dvb_frontend_wakeup(struct dvb_frontend *fe); static void dvb_frontend_wakeup(struct dvb_frontend *fe);
static int dtv_get_frontend(struct dvb_frontend *fe, static int dtv_get_frontend(struct dvb_frontend *fe,
struct dtv_frontend_properties *c,
struct dvb_frontend_parameters *p_out); struct dvb_frontend_parameters *p_out);
static int dtv_property_legacy_params_sync(struct dvb_frontend *fe, static int
dtv_property_legacy_params_sync(struct dvb_frontend *fe,
const struct dtv_frontend_properties *c,
struct dvb_frontend_parameters *p); struct dvb_frontend_parameters *p);
static bool has_get_frontend(struct dvb_frontend *fe) static bool has_get_frontend(struct dvb_frontend *fe)
@ -198,9 +232,11 @@ static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system)
} }
} }
static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) static void dvb_frontend_add_event(struct dvb_frontend *fe,
enum fe_status status)
{ {
struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_frontend_private *fepriv = fe->frontend_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_fe_events *events = &fepriv->events; struct dvb_fe_events *events = &fepriv->events;
struct dvb_frontend_event *e; struct dvb_frontend_event *e;
int wp; int wp;
@ -208,7 +244,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
dev_dbg(fe->dvb->device, "%s:\n", __func__); dev_dbg(fe->dvb->device, "%s:\n", __func__);
if ((status & FE_HAS_LOCK) && has_get_frontend(fe)) if ((status & FE_HAS_LOCK) && has_get_frontend(fe))
dtv_get_frontend(fe, &fepriv->parameters_out); dtv_get_frontend(fe, c, &fepriv->parameters_out);
mutex_lock(&events->mtx); mutex_lock(&events->mtx);
@ -429,7 +465,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
static void dvb_frontend_swzigzag(struct dvb_frontend *fe) static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
{ {
fe_status_t s = 0; enum fe_status s = FE_NONE;
int retval = 0; int retval = 0;
struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_frontend_private *fepriv = fe->frontend_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp; struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp;
@ -565,7 +601,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
{ {
struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_frontend_private *fepriv = fe->frontend_priv;
if (fepriv->exit != DVB_FE_NO_EXIT) if (fe->exit != DVB_FE_NO_EXIT)
return 1; return 1;
if (fepriv->dvbdev->writers == 1) if (fepriv->dvbdev->writers == 1)
@ -598,10 +634,10 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe)
static int dvb_frontend_thread(void *data) static int dvb_frontend_thread(void *data)
{ {
struct dvb_frontend *fe = data; struct dvb_frontend *fe = data;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_frontend_private *fepriv = fe->frontend_priv;
fe_status_t s; enum fe_status s = FE_NONE;
enum dvbfe_algo algo; enum dvbfe_algo algo;
bool re_tune = false; bool re_tune = false;
bool semheld = false; bool semheld = false;
@ -629,7 +665,7 @@ restart:
/* got signal or quitting */ /* got signal or quitting */
if (!down_interruptible(&fepriv->sem)) if (!down_interruptible(&fepriv->sem))
semheld = true; semheld = true;
fepriv->exit = DVB_FE_NORMAL_EXIT; fe->exit = DVB_FE_NORMAL_EXIT;
break; break;
} }
@ -701,7 +737,7 @@ restart:
fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
fepriv->delay = HZ / 2; fepriv->delay = HZ / 2;
} }
dtv_property_legacy_params_sync(fe, &fepriv->parameters_out); dtv_property_legacy_params_sync(fe, c, &fepriv->parameters_out);
fe->ops.read_status(fe, &s); fe->ops.read_status(fe, &s);
if (s != fepriv->status) { if (s != fepriv->status) {
dvb_frontend_add_event(fe, s); /* update event list */ dvb_frontend_add_event(fe, s); /* update event list */
@ -739,9 +775,9 @@ restart:
fepriv->thread = NULL; fepriv->thread = NULL;
if (kthread_should_stop()) if (kthread_should_stop())
fepriv->exit = DVB_FE_DEVICE_REMOVED; fe->exit = DVB_FE_DEVICE_REMOVED;
else else
fepriv->exit = DVB_FE_NO_EXIT; fe->exit = DVB_FE_NO_EXIT;
mb(); mb();
if (semheld) if (semheld)
@ -756,7 +792,8 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
dev_dbg(fe->dvb->device, "%s:\n", __func__); dev_dbg(fe->dvb->device, "%s:\n", __func__);
fepriv->exit = DVB_FE_NORMAL_EXIT; if (fe->exit != DVB_FE_DEVICE_REMOVED)
fe->exit = DVB_FE_NORMAL_EXIT;
mb(); mb();
if (!fepriv->thread) if (!fepriv->thread)
@ -774,43 +811,22 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
fepriv->thread); fepriv->thread);
} }
s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
{
return ((curtime.tv_usec < lasttime.tv_usec) ?
1000000 - lasttime.tv_usec + curtime.tv_usec :
curtime.tv_usec - lasttime.tv_usec);
}
EXPORT_SYMBOL(timeval_usec_diff);
static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec)
{
curtime->tv_usec += add_usec;
if (curtime->tv_usec >= 1000000) {
curtime->tv_usec -= 1000000;
curtime->tv_sec++;
}
}
/* /*
* Sleep until gettimeofday() > waketime + add_usec * Sleep for the amount of time given by add_usec parameter
* This needs to be as precise as possible, but as the delay is *
* usually between 2ms and 32ms, it is done using a scheduled msleep * This needs to be as precise as possible, as it affects the detection of
* followed by usleep (normally a busy-wait loop) for the remainder * the dish tone command at the satellite subsystem. The precision is improved
* by using a scheduled msleep followed by udelay for the remainder.
*/ */
void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec) void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec)
{ {
struct timeval lasttime; s32 delta;
s32 delta, newdelta;
timeval_usec_add(waketime, add_usec); *waketime = ktime_add_us(*waketime, add_usec);
delta = ktime_us_delta(ktime_get_boottime(), *waketime);
do_gettimeofday(&lasttime);
delta = timeval_usec_diff(lasttime, *waketime);
if (delta > 2500) { if (delta > 2500) {
msleep((delta - 1500) / 1000); msleep((delta - 1500) / 1000);
do_gettimeofday(&lasttime); delta = ktime_us_delta(ktime_get_boottime(), *waketime);
newdelta = timeval_usec_diff(lasttime, *waketime);
delta = (newdelta > delta) ? 0 : newdelta;
} }
if (delta > 0) if (delta > 0)
udelay(delta); udelay(delta);
@ -826,7 +842,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
dev_dbg(fe->dvb->device, "%s:\n", __func__); dev_dbg(fe->dvb->device, "%s:\n", __func__);
if (fepriv->thread) { if (fepriv->thread) {
if (fepriv->exit == DVB_FE_NO_EXIT) if (fe->exit == DVB_FE_NO_EXIT)
return 0; return 0;
else else
dvb_frontend_stop (fe); dvb_frontend_stop (fe);
@ -838,7 +854,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
return -EINTR; return -EINTR;
fepriv->state = FESTATE_IDLE; fepriv->state = FESTATE_IDLE;
fepriv->exit = DVB_FE_NO_EXIT; fe->exit = DVB_FE_NO_EXIT;
fepriv->thread = NULL; fepriv->thread = NULL;
mb(); mb();
@ -967,6 +983,11 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
case SYS_ATSC: case SYS_ATSC:
c->modulation = VSB_8; c->modulation = VSB_8;
break; break;
case SYS_ISDBS:
c->symbol_rate = 28860000;
c->rolloff = ROLLOFF_35;
c->bandwidth_hz = c->symbol_rate / 100 * 135;
break;
default: default:
c->modulation = QAM_AUTO; c->modulation = QAM_AUTO;
break; break;
@ -985,6 +1006,17 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
.buffer = b \ .buffer = b \
} }
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 */
};
static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
_DTV_CMD(DTV_TUNE, 1, 0), _DTV_CMD(DTV_TUNE, 1, 0),
_DTV_CMD(DTV_CLEAR, 1, 0), _DTV_CMD(DTV_CLEAR, 1, 0),
@ -1068,18 +1100,24 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
_DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0), _DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0),
}; };
static void dtv_property_dump(struct dvb_frontend *fe, struct dtv_property *tvp) static void dtv_property_dump(struct dvb_frontend *fe,
bool is_set,
struct dtv_property *tvp)
{ {
int i; int i;
if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) { if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
dev_warn(fe->dvb->device, "%s: tvp.cmd = 0x%08x undefined\n", dev_warn(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x undefined\n",
__func__, tvp->cmd); __func__,
is_set ? "SET" : "GET",
tvp->cmd);
return; return;
} }
dev_dbg(fe->dvb->device, "%s: tvp.cmd = 0x%08x (%s)\n", __func__, dev_dbg(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x (%s)\n", __func__,
tvp->cmd, dtv_cmds[tvp->cmd].name); is_set ? "SET" : "GET",
tvp->cmd,
dtv_cmds[tvp->cmd].name);
if (dtv_cmds[tvp->cmd].buffer) { if (dtv_cmds[tvp->cmd].buffer) {
dev_dbg(fe->dvb->device, "%s: tvp.u.buffer.len = 0x%02x\n", dev_dbg(fe->dvb->device, "%s: tvp.u.buffer.len = 0x%02x\n",
@ -1174,11 +1212,11 @@ static int dtv_property_cache_sync(struct dvb_frontend *fe,
/* Ensure the cached values are set correctly in the frontend /* Ensure the cached values are set correctly in the frontend
* legacy tuning structures, for the advanced tuning API. * legacy tuning structures, for the advanced tuning API.
*/ */
static int dtv_property_legacy_params_sync(struct dvb_frontend *fe, static int
dtv_property_legacy_params_sync(struct dvb_frontend *fe,
const struct dtv_frontend_properties *c,
struct dvb_frontend_parameters *p) struct dvb_frontend_parameters *p)
{ {
const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
p->frequency = c->frequency; p->frequency = c->frequency;
p->inversion = c->inversion; p->inversion = c->inversion;
@ -1250,16 +1288,17 @@ static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
* If p_out is not null, it will update the DVBv3 params pointed by it. * If p_out is not null, it will update the DVBv3 params pointed by it.
*/ */
static int dtv_get_frontend(struct dvb_frontend *fe, static int dtv_get_frontend(struct dvb_frontend *fe,
struct dtv_frontend_properties *c,
struct dvb_frontend_parameters *p_out) struct dvb_frontend_parameters *p_out)
{ {
int r; int r;
if (fe->ops.get_frontend) { if (fe->ops.get_frontend) {
r = fe->ops.get_frontend(fe); r = fe->ops.get_frontend(fe, c);
if (unlikely(r < 0)) if (unlikely(r < 0))
return r; return r;
if (p_out) if (p_out)
dtv_property_legacy_params_sync(fe, p_out); dtv_property_legacy_params_sync(fe, c, p_out);
return 0; return 0;
} }
@ -1282,7 +1321,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
switch(tvp->cmd) { switch(tvp->cmd) {
case DTV_ENUM_DELSYS: case DTV_ENUM_DELSYS:
ncaps = 0; ncaps = 0;
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) {
tvp->u.buffer.data[ncaps] = fe->ops.delsys[ncaps]; tvp->u.buffer.data[ncaps] = fe->ops.delsys[ncaps];
ncaps++; ncaps++;
} }
@ -1507,7 +1546,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
return r; return r;
} }
dtv_property_dump(fe, tvp); dtv_property_dump(fe, false, tvp);
return 0; return 0;
} }
@ -1516,12 +1555,8 @@ static int dtv_set_frontend(struct dvb_frontend *fe);
static bool is_dvbv3_delsys(u32 delsys) static bool is_dvbv3_delsys(u32 delsys)
{ {
bool status; return (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) ||
status = (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) ||
(delsys == SYS_DVBS) || (delsys == SYS_ATSC); (delsys == SYS_DVBS) || (delsys == SYS_ATSC);
return status;
} }
/** /**
@ -1611,7 +1646,7 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
* supported * supported
*/ */
ncaps = 0; ncaps = 0;
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) {
if (fe->ops.delsys[ncaps] == desired_system) { if (fe->ops.delsys[ncaps] == desired_system) {
c->delivery_system = desired_system; c->delivery_system = desired_system;
dev_dbg(fe->dvb->device, dev_dbg(fe->dvb->device,
@ -1643,7 +1678,7 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
* of the desired system * of the desired system
*/ */
ncaps = 0; ncaps = 0;
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) {
if (dvbv3_type(fe->ops.delsys[ncaps]) == type) if (dvbv3_type(fe->ops.delsys[ncaps]) == type)
delsys = fe->ops.delsys[ncaps]; delsys = fe->ops.delsys[ncaps];
ncaps++; ncaps++;
@ -1718,7 +1753,7 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe)
* DVBv3 standard * DVBv3 standard
*/ */
ncaps = 0; ncaps = 0;
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) {
if (dvbv3_type(fe->ops.delsys[ncaps]) != DVBV3_UNKNOWN) { if (dvbv3_type(fe->ops.delsys[ncaps]) != DVBV3_UNKNOWN) {
delsys = fe->ops.delsys[ncaps]; delsys = fe->ops.delsys[ncaps];
break; break;
@ -1748,6 +1783,8 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
return r; return r;
} }
dtv_property_dump(fe, true, tvp);
switch(tvp->cmd) { switch(tvp->cmd) {
case DTV_CLEAR: case DTV_CLEAR:
/* /*
@ -1931,7 +1968,7 @@ static int dvb_frontend_ioctl(struct file *file,
if (down_interruptible(&fepriv->sem)) if (down_interruptible(&fepriv->sem))
return -ERESTARTSYS; return -ERESTARTSYS;
if (fepriv->exit != DVB_FE_NO_EXIT) { if (fe->exit != DVB_FE_NO_EXIT) {
up(&fepriv->sem); up(&fepriv->sem);
return -ENODEV; return -ENODEV;
} }
@ -1963,15 +2000,13 @@ static int dvb_frontend_ioctl_properties(struct file *file,
struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int err = 0; int err = 0;
struct dtv_properties *tvps = NULL; struct dtv_properties *tvps = parg;
struct dtv_property *tvp = NULL; struct dtv_property *tvp = NULL;
int i; int i;
dev_dbg(fe->dvb->device, "%s:\n", __func__); dev_dbg(fe->dvb->device, "%s:\n", __func__);
if (cmd == FE_SET_PROPERTY) { if (cmd == FE_SET_PROPERTY) {
tvps = (struct dtv_properties __user *)parg;
dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num); dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props); dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
@ -1980,16 +2015,9 @@ static int dvb_frontend_ioctl_properties(struct file *file,
if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
return -EINVAL; return -EINVAL;
tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL); tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
if (!tvp) { if (IS_ERR(tvp))
err = -ENOMEM; return PTR_ERR(tvp);
goto out;
}
if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
err = -EFAULT;
goto out;
}
for (i = 0; i < tvps->num; i++) { for (i = 0; i < tvps->num; i++) {
err = dtv_property_process_set(fe, tvp + i, file); err = dtv_property_process_set(fe, tvp + i, file);
@ -2001,9 +2029,8 @@ static int dvb_frontend_ioctl_properties(struct file *file,
if (c->state == DTV_TUNE) if (c->state == DTV_TUNE)
dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__); dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__);
} else } else if (cmd == FE_GET_PROPERTY) {
if(cmd == FE_GET_PROPERTY) { struct dtv_frontend_properties getp = fe->dtv_property_cache;
tvps = (struct dtv_properties __user *)parg;
dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num); dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props); dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
@ -2013,35 +2040,30 @@ static int dvb_frontend_ioctl_properties(struct file *file,
if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
return -EINVAL; return -EINVAL;
tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL); tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
if (!tvp) { if (IS_ERR(tvp))
err = -ENOMEM; return PTR_ERR(tvp);
goto out;
}
if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
err = -EFAULT;
goto out;
}
/* /*
* Fills the cache out struct with the cache contents, plus * Let's use our own copy of property cache, in order to
* the data retrieved from get_frontend, if the frontend * avoid mangling with DTV zigzag logic, as drivers might
* is not idle. Otherwise, returns the cached content * return crap, if they don't check if the data is available
* before updating the properties cache.
*/ */
if (fepriv->state != FESTATE_IDLE) { if (fepriv->state != FESTATE_IDLE) {
err = dtv_get_frontend(fe, NULL); err = dtv_get_frontend(fe, &getp, NULL);
if (err < 0) if (err < 0)
goto out; goto out;
} }
for (i = 0; i < tvps->num; i++) { for (i = 0; i < tvps->num; i++) {
err = dtv_property_process_get(fe, c, tvp + i, file); err = dtv_property_process_get(fe, &getp, tvp + i, file);
if (err < 0) if (err < 0)
goto out; goto out;
(tvp + i)->result = err; (tvp + i)->result = err;
} }
if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) { if (copy_to_user((void __user *)tvps->props, tvp,
tvps->num * sizeof(struct dtv_property))) {
err = -EFAULT; err = -EFAULT;
goto out; goto out;
} }
@ -2069,7 +2091,7 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
* the user. FE_SET_FRONTEND triggers an initial frontend event * the user. FE_SET_FRONTEND triggers an initial frontend event
* with status = 0, which copies output parameters to userspace. * with status = 0, which copies output parameters to userspace.
*/ */
dtv_property_legacy_params_sync(fe, &fepriv->parameters_out); dtv_property_legacy_params_sync(fe, c, &fepriv->parameters_out);
/* /*
* Be sure that the bandwidth will be filled for all * Be sure that the bandwidth will be filled for all
@ -2101,11 +2123,29 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
case SYS_DVBC_ANNEX_C: case SYS_DVBC_ANNEX_C:
rolloff = 113; rolloff = 113;
break; break;
case SYS_DVBS:
case SYS_TURBO:
case SYS_ISDBS:
rolloff = 135;
break;
case SYS_DVBS2:
switch (c->rolloff) {
case ROLLOFF_20:
rolloff = 120;
break;
case ROLLOFF_25:
rolloff = 125;
break;
default:
case ROLLOFF_35:
rolloff = 135;
}
break;
default: default:
break; break;
} }
if (rolloff) if (rolloff)
c->bandwidth_hz = (c->symbol_rate * rolloff) / 100; c->bandwidth_hz = mult_frac(c->symbol_rate, rolloff, 100);
/* force auto frequency inversion if requested */ /* force auto frequency inversion if requested */
if (dvb_force_auto_inversion) if (dvb_force_auto_inversion)
@ -2222,15 +2262,15 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
dev_dbg(fe->dvb->device, "%s: current delivery system on cache: %d, V3 type: %d\n", dev_dbg(fe->dvb->device, "%s: current delivery system on cache: %d, V3 type: %d\n",
__func__, c->delivery_system, fe->ops.info.type); __func__, c->delivery_system, fe->ops.info.type);
/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't /* Set CAN_INVERSION_AUTO bit on in other than oneshot mode */
* do it, it is done for it. */ if (!(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT))
info->caps |= FE_CAN_INVERSION_AUTO; info->caps |= FE_CAN_INVERSION_AUTO;
err = 0; err = 0;
break; break;
} }
case FE_READ_STATUS: { case FE_READ_STATUS: {
fe_status_t* status = parg; enum fe_status *status = parg;
/* if retune was requested but hasn't occurred yet, prevent /* if retune was requested but hasn't occurred yet, prevent
* that user get signal state from previous tuning */ * that user get signal state from previous tuning */
@ -2292,7 +2332,13 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
case FE_DISEQC_SEND_MASTER_CMD: case FE_DISEQC_SEND_MASTER_CMD:
if (fe->ops.diseqc_send_master_cmd) { if (fe->ops.diseqc_send_master_cmd) {
err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg); struct dvb_diseqc_master_cmd *cmd = parg;
if (cmd->msg_len > sizeof(cmd->msg)) {
err = -EINVAL;
break;
}
err = fe->ops.diseqc_send_master_cmd(fe, cmd);
fepriv->state = FESTATE_DISEQC; fepriv->state = FESTATE_DISEQC;
fepriv->status = 0; fepriv->status = 0;
} }
@ -2300,7 +2346,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
case FE_DISEQC_SEND_BURST: case FE_DISEQC_SEND_BURST:
if (fe->ops.diseqc_send_burst) { if (fe->ops.diseqc_send_burst) {
err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg); err = fe->ops.diseqc_send_burst(fe,
(enum fe_sec_mini_cmd)parg);
fepriv->state = FESTATE_DISEQC; fepriv->state = FESTATE_DISEQC;
fepriv->status = 0; fepriv->status = 0;
} }
@ -2308,8 +2355,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
case FE_SET_TONE: case FE_SET_TONE:
if (fe->ops.set_tone) { if (fe->ops.set_tone) {
err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg); err = fe->ops.set_tone(fe,
fepriv->tone = (fe_sec_tone_mode_t) parg; (enum fe_sec_tone_mode)parg);
fepriv->tone = (enum fe_sec_tone_mode)parg;
fepriv->state = FESTATE_DISEQC; fepriv->state = FESTATE_DISEQC;
fepriv->status = 0; fepriv->status = 0;
} }
@ -2317,8 +2365,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
case FE_SET_VOLTAGE: case FE_SET_VOLTAGE:
if (fe->ops.set_voltage) { if (fe->ops.set_voltage) {
err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg); err = fe->ops.set_voltage(fe,
fepriv->voltage = (fe_sec_voltage_t) parg; (enum fe_sec_voltage)parg);
fepriv->voltage = (enum fe_sec_voltage)parg;
fepriv->state = FESTATE_DISEQC; fepriv->state = FESTATE_DISEQC;
fepriv->status = 0; fepriv->status = 0;
} }
@ -2326,7 +2375,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
case FE_DISHNETWORK_SEND_LEGACY_CMD: case FE_DISHNETWORK_SEND_LEGACY_CMD:
if (fe->ops.dishnetwork_send_legacy_command) { if (fe->ops.dishnetwork_send_legacy_command) {
err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg); err = fe->ops.dishnetwork_send_legacy_command(fe,
(unsigned long)parg);
fepriv->state = FESTATE_DISEQC; fepriv->state = FESTATE_DISEQC;
fepriv->status = 0; fepriv->status = 0;
} else if (fe->ops.set_voltage) { } else if (fe->ops.set_voltage) {
@ -2347,13 +2397,14 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
* include the initialization or start bit * include the initialization or start bit
*/ */
unsigned long swcmd = ((unsigned long) parg) << 1; unsigned long swcmd = ((unsigned long) parg) << 1;
struct timeval nexttime; ktime_t nexttime;
struct timeval tv[10]; ktime_t tv[10];
int i; int i;
u8 last = 1; u8 last = 1;
if (dvb_frontend_debug) if (dvb_frontend_debug)
printk("%s switch command: 0x%04lx\n", __func__, swcmd); dprintk("%s switch command: 0x%04lx\n",
do_gettimeofday(&nexttime); __func__, swcmd);
nexttime = ktime_get_boottime();
if (dvb_frontend_debug) if (dvb_frontend_debug)
tv[0] = nexttime; tv[0] = nexttime;
/* before sending a command, initialize by sending /* before sending a command, initialize by sending
@ -2364,7 +2415,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
for (i = 0; i < 9; i++) { for (i = 0; i < 9; i++) {
if (dvb_frontend_debug) if (dvb_frontend_debug)
do_gettimeofday(&tv[i + 1]); tv[i+1] = ktime_get_boottime();
if ((swcmd & 0x01) != last) { if ((swcmd & 0x01) != last) {
/* set voltage to (last ? 13V : 18V) */ /* set voltage to (last ? 13V : 18V) */
fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
@ -2375,10 +2426,11 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
dvb_frontend_sleep_until(&nexttime, 8000); dvb_frontend_sleep_until(&nexttime, 8000);
} }
if (dvb_frontend_debug) { if (dvb_frontend_debug) {
printk("%s(%d): switch delay (should be 32k followed by all 8k\n", dprintk("%s(%d): switch delay (should be 32k followed by all 8k)\n",
__func__, fe->dvb->num); __func__, fe->dvb->num);
for (i = 1; i < 10; i++) for (i = 1; i < 10; i++)
printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i])); pr_info("%d: %d\n", i,
(int) ktime_us_delta(tv[i], tv[i-1]));
} }
err = 0; err = 0;
fepriv->state = FESTATE_DISEQC; fepriv->state = FESTATE_DISEQC;
@ -2410,10 +2462,18 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
err = dvb_frontend_get_event (fe, parg, file->f_flags); err = dvb_frontend_get_event (fe, parg, file->f_flags);
break; break;
case FE_GET_FRONTEND: case FE_GET_FRONTEND: {
err = dtv_get_frontend(fe, parg); struct dtv_frontend_properties getp = fe->dtv_property_cache;
break;
/*
* Let's use our own copy of property cache, in order to
* avoid mangling with DTV zigzag logic, as drivers might
* return crap, if they don't check if the data is available
* before updating the properties cache.
*/
err = dtv_get_frontend(fe, &getp, parg);
break;
}
case FE_SET_FRONTEND_TUNE_MODE: case FE_SET_FRONTEND_TUNE_MODE:
fepriv->tune_mode_flags = (unsigned long) parg; fepriv->tune_mode_flags = (unsigned long) parg;
err = 0; err = 0;
@ -2430,7 +2490,7 @@ static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struc
struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend *fe = dvbdev->priv;
struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_frontend_private *fepriv = fe->frontend_priv;
//dev_dbg_ratelimited(fe->dvb->device, "%s:\n", __func__); dev_dbg_ratelimited(fe->dvb->device, "%s:\n", __func__);
poll_wait (file, &fepriv->events.wait_queue, wait); poll_wait (file, &fepriv->events.wait_queue, wait);
@ -2449,7 +2509,7 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
int ret; int ret;
dev_dbg(fe->dvb->device, "%s:\n", __func__); dev_dbg(fe->dvb->device, "%s:\n", __func__);
if (fepriv->exit == DVB_FE_DEVICE_REMOVED) if (fe->exit == DVB_FE_DEVICE_REMOVED)
return -ENODEV; return -ENODEV;
if (adapter->mfe_shared) { if (adapter->mfe_shared) {
@ -2513,19 +2573,45 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
fepriv->tone = -1; fepriv->tone = -1;
fepriv->voltage = -1; fepriv->voltage = -1;
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
if (fe->dvb->mdev) {
mutex_lock(&fe->dvb->mdev->graph_mutex);
if (fe->dvb->mdev->enable_source)
ret = fe->dvb->mdev->enable_source(
dvbdev->entity,
&fepriv->pipe);
mutex_unlock(&fe->dvb->mdev->graph_mutex);
if (ret) {
dev_err(fe->dvb->device,
"Tuner is busy. Error %d\n", ret);
goto err2;
}
}
#endif
ret = dvb_frontend_start (fe); ret = dvb_frontend_start (fe);
if (ret) if (ret)
goto err2; goto err3;
/* empty event queue */ /* empty event queue */
fepriv->events.eventr = fepriv->events.eventw = 0; fepriv->events.eventr = fepriv->events.eventw = 0;
} }
dvb_frontend_get(fe);
if (adapter->mfe_shared) if (adapter->mfe_shared)
mutex_unlock (&adapter->mfe_lock); mutex_unlock (&adapter->mfe_lock);
return ret; return ret;
err3:
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
if (fe->dvb->mdev) {
mutex_lock(&fe->dvb->mdev->graph_mutex);
if (fe->dvb->mdev->disable_source)
fe->dvb->mdev->disable_source(dvbdev->entity);
mutex_unlock(&fe->dvb->mdev->graph_mutex);
}
err2: err2:
#endif
dvb_generic_release(inode, file); dvb_generic_release(inode, file);
err1: err1:
if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
@ -2554,12 +2640,22 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
if (dvbdev->users == -1) { if (dvbdev->users == -1) {
wake_up(&fepriv->wait_queue); wake_up(&fepriv->wait_queue);
if (fepriv->exit != DVB_FE_NO_EXIT) #ifdef CONFIG_MEDIA_CONTROLLER_DVB
if (fe->dvb->mdev) {
mutex_lock(&fe->dvb->mdev->graph_mutex);
if (fe->dvb->mdev->disable_source)
fe->dvb->mdev->disable_source(dvbdev->entity);
mutex_unlock(&fe->dvb->mdev->graph_mutex);
}
#endif
if (fe->exit != DVB_FE_NO_EXIT)
wake_up(&dvbdev->wait_queue); wake_up(&dvbdev->wait_queue);
if (fe->ops.ts_bus_ctrl) if (fe->ops.ts_bus_ctrl)
fe->ops.ts_bus_ctrl(fe, 0); fe->ops.ts_bus_ctrl(fe, 0);
} }
dvb_frontend_put(fe);
return ret; return ret;
} }
@ -2579,7 +2675,9 @@ int dvb_frontend_suspend(struct dvb_frontend *fe)
dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num, dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num,
fe->id); fe->id);
if (fe->ops.tuner_ops.sleep) if (fe->ops.tuner_ops.suspend)
ret = fe->ops.tuner_ops.suspend(fe);
else if (fe->ops.tuner_ops.sleep)
ret = fe->ops.tuner_ops.sleep(fe); ret = fe->ops.tuner_ops.sleep(fe);
if (fe->ops.sleep) if (fe->ops.sleep)
@ -2597,12 +2695,21 @@ int dvb_frontend_resume(struct dvb_frontend *fe)
dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num, dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num,
fe->id); fe->id);
fe->exit = DVB_FE_DEVICE_RESUME;
if (fe->ops.init) if (fe->ops.init)
ret = fe->ops.init(fe); ret = fe->ops.init(fe);
if (fe->ops.tuner_ops.init) if (fe->ops.tuner_ops.resume)
ret = fe->ops.tuner_ops.resume(fe);
else if (fe->ops.tuner_ops.init)
ret = fe->ops.tuner_ops.init(fe); ret = fe->ops.tuner_ops.init(fe);
if (fe->ops.set_tone && fepriv->tone != -1)
fe->ops.set_tone(fe, fepriv->tone);
if (fe->ops.set_voltage && fepriv->voltage != -1)
fe->ops.set_voltage(fe, fepriv->voltage);
fe->exit = DVB_FE_NO_EXIT;
fepriv->state = FESTATE_RETUNE; fepriv->state = FESTATE_RETUNE;
dvb_frontend_wakeup(fe); dvb_frontend_wakeup(fe);
@ -2614,11 +2721,14 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
struct dvb_frontend* fe) struct dvb_frontend* fe)
{ {
struct dvb_frontend_private *fepriv; struct dvb_frontend_private *fepriv;
static const struct dvb_device dvbdev_template = { const struct dvb_device dvbdev_template = {
.users = ~0, .users = ~0,
.writers = 1, .writers = 1,
.readers = (~0)-1, .readers = (~0)-1,
.fops = &dvb_frontend_fops, .fops = &dvb_frontend_fops,
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
.name = fe->ops.info.name,
#endif
.kernel_ioctl = dvb_frontend_ioctl .kernel_ioctl = dvb_frontend_ioctl
}; };
@ -2634,6 +2744,15 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
} }
fepriv = fe->frontend_priv; fepriv = fe->frontend_priv;
kref_init(&fe->refcount);
/*
* After initialization, there need to be two references: one
* for dvb_unregister_frontend(), and another one for
* dvb_frontend_detach().
*/
dvb_frontend_get(fe);
sema_init(&fepriv->sem, 1); sema_init(&fepriv->sem, 1);
init_waitqueue_head (&fepriv->wait_queue); init_waitqueue_head (&fepriv->wait_queue);
init_waitqueue_head (&fepriv->events.wait_queue); init_waitqueue_head (&fepriv->events.wait_queue);
@ -2642,7 +2761,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
fepriv->inversion = INVERSION_OFF; fepriv->inversion = INVERSION_OFF;
dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template, dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
fe, DVB_DEVICE_FRONTEND); fe, DVB_DEVICE_FRONTEND, 0);
dev_info(fe->dvb->device, dev_info(fe->dvb->device,
"DVB: registering adapter %i frontend %i (%s)...\n", "DVB: registering adapter %i frontend %i (%s)...\n",
@ -2668,56 +2787,32 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
mutex_lock(&frontend_mutex); mutex_lock(&frontend_mutex);
dvb_frontend_stop(fe); dvb_frontend_stop(fe);
mutex_unlock(&frontend_mutex); dvb_remove_device(fepriv->dvbdev);
if (fepriv->dvbdev->users < -1)
wait_event(fepriv->dvbdev->wait_queue,
fepriv->dvbdev->users==-1);
mutex_lock(&frontend_mutex);
dvb_unregister_device (fepriv->dvbdev);
/* fe is invalid now */ /* fe is invalid now */
kfree(fepriv);
mutex_unlock(&frontend_mutex); mutex_unlock(&frontend_mutex);
dvb_frontend_put(fe);
return 0; return 0;
} }
EXPORT_SYMBOL(dvb_unregister_frontend); EXPORT_SYMBOL(dvb_unregister_frontend);
static void dvb_frontend_invoke_release(struct dvb_frontend *fe,
void (*release)(struct dvb_frontend *fe))
{
if (release) {
release(fe);
#ifdef CONFIG_MEDIA_ATTACH #ifdef CONFIG_MEDIA_ATTACH
void dvb_frontend_detach(struct dvb_frontend* fe) dvb_detach(release);
{
void *ptr;
if (fe->ops.release_sec) {
fe->ops.release_sec(fe);
symbol_put_addr(fe->ops.release_sec);
}
if (fe->ops.tuner_ops.release) {
fe->ops.tuner_ops.release(fe);
symbol_put_addr(fe->ops.tuner_ops.release);
}
if (fe->ops.analog_ops.release) {
fe->ops.analog_ops.release(fe);
symbol_put_addr(fe->ops.analog_ops.release);
}
ptr = (void*)fe->ops.release;
if (ptr) {
fe->ops.release(fe);
symbol_put_addr(ptr);
}
}
#else
void dvb_frontend_detach(struct dvb_frontend* fe)
{
if (fe->ops.release_sec)
fe->ops.release_sec(fe);
if (fe->ops.tuner_ops.release)
fe->ops.tuner_ops.release(fe);
if (fe->ops.analog_ops.release)
fe->ops.analog_ops.release(fe);
if (fe->ops.release)
fe->ops.release(fe);
}
#endif #endif
}
}
void dvb_frontend_detach(struct dvb_frontend* fe)
{
dvb_frontend_invoke_release(fe, fe->ops.release_sec);
dvb_frontend_invoke_release(fe, fe->ops.tuner_ops.release);
dvb_frontend_invoke_release(fe, fe->ops.analog_ops.release);
dvb_frontend_invoke_release(fe, fe->ops.detach);
dvb_frontend_put(fe);
}
EXPORT_SYMBOL(dvb_frontend_detach); EXPORT_SYMBOL(dvb_frontend_detach);

View File

@ -1,6 +1,10 @@
/* /*
* dvb_frontend.h * dvb_frontend.h
* *
* The Digital TV Frontend kABI defines a driver-internal interface for
* registering low-level, hardware specific driver to a hardware independent
* frontend layer.
*
* Copyright (C) 2001 convergence integrated media GmbH * Copyright (C) 2001 convergence integrated media GmbH
* Copyright (C) 2004 convergence GmbH * Copyright (C) 2004 convergence GmbH
* *
@ -53,6 +57,15 @@
*/ */
#define MAX_DELSYS 8 #define MAX_DELSYS 8
/**
* struct dvb_frontend_tune_settings - parameters to adjust frontend tuning
*
* @min_delay_ms: minimum delay for tuning, in ms
* @step_size: step size between two consecutive frequencies
* @max_drift: maximum drift
*
* NOTE: step_size is in Hz, for terrestrial/cable or kHz for satellite
*/
struct dvb_frontend_tune_settings { struct dvb_frontend_tune_settings {
int min_delay_ms; int min_delay_ms;
int step_size; int step_size;
@ -61,6 +74,20 @@ struct dvb_frontend_tune_settings {
struct dvb_frontend; struct dvb_frontend;
/**
* struct dvb_tuner_info - Frontend name and min/max ranges/bandwidths
*
* @name: name of the Frontend
* @frequency_min: minimal frequency supported
* @frequency_max: maximum frequency supported
* @frequency_step: frequency step
* @bandwidth_min: minimal frontend bandwidth supported
* @bandwidth_max: maximum frontend bandwidth supported
* @bandwidth_step: frontend bandwidth step
*
* NOTE: frequency parameters are in Hz, for terrestrial/cable or kHz for
* satellite.
*/
struct dvb_tuner_info { struct dvb_tuner_info {
char name[128]; char name[128];
@ -73,6 +100,20 @@ struct dvb_tuner_info {
u32 bandwidth_step; u32 bandwidth_step;
}; };
/**
* struct analog_parameters - Parameters to tune into an analog/radio channel
*
* @frequency: Frequency used by analog TV tuner (either in 62.5 kHz step,
* for TV, or 62.5 Hz for radio)
* @mode: Tuner mode, as defined on enum v4l2_tuner_type
* @audmode: Audio mode as defined for the rxsubchans field at videodev2.h,
* e. g. V4L2_TUNER_MODE_*
* @std: TV standard bitmap as defined at videodev2.h, e. g. V4L2_STD_*
*
* Hybrid tuners should be supported by both V4L2 and DVB APIs. This
* struct contains the data that are used by the V4L2 side. To avoid
* dependencies from V4L2 headers, all enums here are declared as integers.
*/
struct analog_parameters { struct analog_parameters {
unsigned int frequency; unsigned int frequency;
unsigned int mode; unsigned int mode;
@ -80,66 +121,19 @@ struct analog_parameters {
u64 std; u64 std;
}; };
enum dvbfe_modcod { /**
DVBFE_MODCOD_DUMMY_PLFRAME = 0, * enum dvbfe_algo - defines the algorithm used to tune into a channel
DVBFE_MODCOD_QPSK_1_4, *
DVBFE_MODCOD_QPSK_1_3, * @DVBFE_ALGO_HW: Hardware Algorithm -
DVBFE_MODCOD_QPSK_2_5,
DVBFE_MODCOD_QPSK_1_2,
DVBFE_MODCOD_QPSK_3_5,
DVBFE_MODCOD_QPSK_2_3,
DVBFE_MODCOD_QPSK_3_4,
DVBFE_MODCOD_QPSK_4_5,
DVBFE_MODCOD_QPSK_5_6,
DVBFE_MODCOD_QPSK_8_9,
DVBFE_MODCOD_QPSK_9_10,
DVBFE_MODCOD_8PSK_3_5,
DVBFE_MODCOD_8PSK_2_3,
DVBFE_MODCOD_8PSK_3_4,
DVBFE_MODCOD_8PSK_5_6,
DVBFE_MODCOD_8PSK_8_9,
DVBFE_MODCOD_8PSK_9_10,
DVBFE_MODCOD_16APSK_2_3,
DVBFE_MODCOD_16APSK_3_4,
DVBFE_MODCOD_16APSK_4_5,
DVBFE_MODCOD_16APSK_5_6,
DVBFE_MODCOD_16APSK_8_9,
DVBFE_MODCOD_16APSK_9_10,
DVBFE_MODCOD_32APSK_3_4,
DVBFE_MODCOD_32APSK_4_5,
DVBFE_MODCOD_32APSK_5_6,
DVBFE_MODCOD_32APSK_8_9,
DVBFE_MODCOD_32APSK_9_10,
DVBFE_MODCOD_RESERVED_1,
DVBFE_MODCOD_BPSK_1_3,
DVBFE_MODCOD_BPSK_1_4,
DVBFE_MODCOD_RESERVED_2
};
enum tuner_param {
DVBFE_TUNER_FREQUENCY = (1 << 0),
DVBFE_TUNER_TUNERSTEP = (1 << 1),
DVBFE_TUNER_IFFREQ = (1 << 2),
DVBFE_TUNER_BANDWIDTH = (1 << 3),
DVBFE_TUNER_REFCLOCK = (1 << 4),
DVBFE_TUNER_IQSENSE = (1 << 5),
DVBFE_TUNER_DUMMY = (1 << 31)
};
/*
* ALGO_HW: (Hardware Algorithm)
* ----------------------------------------------------------------
* Devices that support this algorithm do everything in hardware * Devices that support this algorithm do everything in hardware
* and no software support is needed to handle them. * and no software support is needed to handle them.
* Requesting these devices to LOCK is the only thing required, * Requesting these devices to LOCK is the only thing required,
* device is supposed to do everything in the hardware. * device is supposed to do everything in the hardware.
* *
* ALGO_SW: (Software Algorithm) * @DVBFE_ALGO_SW: Software Algorithm -
* ----------------------------------------------------------------
* These are dumb devices, that require software to do everything * These are dumb devices, that require software to do everything
* *
* ALGO_CUSTOM: (Customizable Agorithm) * @DVBFE_ALGO_CUSTOM: Customizable Agorithm -
* ----------------------------------------------------------------
* Devices having this algorithm can be customized to have specific * Devices having this algorithm can be customized to have specific
* algorithms in the frontend driver, rather than simply doing a * algorithms in the frontend driver, rather than simply doing a
* software zig-zag. In this case the zigzag maybe hardware assisted * software zig-zag. In this case the zigzag maybe hardware assisted
@ -147,8 +141,7 @@ enum tuner_param {
* this algorithm, in conjunction with the search and track * this algorithm, in conjunction with the search and track
* callbacks, utilizes the driver specific algorithm. * callbacks, utilizes the driver specific algorithm.
* *
* ALGO_RECOVERY: (Recovery Algorithm) * @DVBFE_ALGO_RECOVERY: Recovery Algorithm -
* ----------------------------------------------------------------
* These devices have AUTO recovery capabilities from LOCK failure * These devices have AUTO recovery capabilities from LOCK failure
*/ */
enum dvbfe_algo { enum dvbfe_algo {
@ -158,35 +151,26 @@ enum dvbfe_algo {
DVBFE_ALGO_RECOVERY = (1 << 31) DVBFE_ALGO_RECOVERY = (1 << 31)
}; };
struct tuner_state { /**
u32 frequency; * enum dvbfe_search - search callback possible return status
u32 tunerstep;
u32 ifreq;
u32 bandwidth;
u32 iqsense;
u32 refclock;
};
/*
* search callback possible return status
* *
* DVBFE_ALGO_SEARCH_SUCCESS * @DVBFE_ALGO_SEARCH_SUCCESS:
* The frontend search algorithm completed and returned successfully * The frontend search algorithm completed and returned successfully
* *
* DVBFE_ALGO_SEARCH_ASLEEP * @DVBFE_ALGO_SEARCH_ASLEEP:
* The frontend search algorithm is sleeping * The frontend search algorithm is sleeping
* *
* DVBFE_ALGO_SEARCH_FAILED * @DVBFE_ALGO_SEARCH_FAILED:
* The frontend search for a signal failed * The frontend search for a signal failed
* *
* DVBFE_ALGO_SEARCH_INVALID * @DVBFE_ALGO_SEARCH_INVALID:
* The frontend search algorith was probably supplied with invalid * The frontend search algorith was probably supplied with invalid
* parameters and the search is an invalid one * parameters and the search is an invalid one
* *
* DVBFE_ALGO_SEARCH_ERROR * @DVBFE_ALGO_SEARCH_ERROR:
* The frontend search algorithm failed due to some error * The frontend search algorithm failed due to some error
* *
* DVBFE_ALGO_SEARCH_AGAIN * @DVBFE_ALGO_SEARCH_AGAIN:
* The frontend search algorithm was requested to search again * The frontend search algorithm was requested to search again
*/ */
enum dvbfe_search { enum dvbfe_search {
@ -198,23 +182,64 @@ enum dvbfe_search {
DVBFE_ALGO_SEARCH_ERROR = (1 << 31), DVBFE_ALGO_SEARCH_ERROR = (1 << 31),
}; };
/**
* struct dvb_tuner_ops - Tuner information and callbacks
*
* @info: embedded struct dvb_tuner_info with tuner properties
* @release: callback function called when frontend is dettached.
* drivers should free any allocated memory.
* @init: callback function used to initialize the tuner device.
* @sleep: callback function used to put the tuner to sleep.
* @suspend: callback function used to inform that the Kernel will
* suspend.
* @resume: callback function used to inform that the Kernel is
* resuming from suspend.
* @set_params: callback function used to inform the tuner to tune
* into a digital TV channel. The properties to be used
* are stored at @dvb_frontend.dtv_property_cache;. The
* tuner demod can change the parameters to reflect the
* changes needed for the channel to be tuned, and
* update statistics. This is the recommended way to set
* the tuner parameters and should be used on newer
* drivers.
* @set_analog_params: callback function used to tune into an analog TV
* channel on hybrid tuners. It passes @analog_parameters;
* to the driver.
* @set_config: callback function used to send some tuner-specific
* parameters.
* @get_frequency: get the actual tuned frequency
* @get_bandwidth: get the bandwitdh used by the low pass filters
* @get_if_frequency: get the Intermediate Frequency, in Hz. For baseband,
* should return 0.
* @get_status: returns the frontend lock status
* @get_rf_strength: returns the RF signal strengh. Used mostly to support
* analog TV and radio. Digital TV should report, instead,
* via DVBv5 API (@dvb_frontend.dtv_property_cache;).
* @get_afc: Used only by analog TV core. Reports the frequency
* drift due to AFC.
* @calc_regs: callback function used to pass register data settings
* for simple tuners. Shouldn't be used on newer drivers.
* @set_frequency: Set a new frequency. Shouldn't be used on newer drivers.
* @set_bandwidth: Set a new frequency. Shouldn't be used on newer drivers.
*
* NOTE: frequencies used on get_frequency and set_frequency are in Hz for
* terrestrial/cable or kHz for satellite.
*
*/
struct dvb_tuner_ops { struct dvb_tuner_ops {
struct dvb_tuner_info info; struct dvb_tuner_info info;
int (*release)(struct dvb_frontend *fe); void (*release)(struct dvb_frontend *fe);
int (*init)(struct dvb_frontend *fe); int (*init)(struct dvb_frontend *fe);
int (*sleep)(struct dvb_frontend *fe); int (*sleep)(struct dvb_frontend *fe);
int (*suspend)(struct dvb_frontend *fe);
int (*resume)(struct dvb_frontend *fe);
/** This is for simple PLLs - set all parameters in one go. */ /* This is the recomended way to set the tuner */
int (*set_params)(struct dvb_frontend *fe); int (*set_params)(struct dvb_frontend *fe);
int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p); int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
/** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len);
/** This is to allow setting tuner-specific configs */
int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency); int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
@ -227,23 +252,56 @@ struct dvb_tuner_ops {
int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength); int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
int (*get_afc)(struct dvb_frontend *fe, s32 *afc); int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
/** These are provided separately from set_params in order to facilitate silicon /*
* tuners which require sophisticated tuning loops, controlling each parameter separately. */ * This is support for demods like the mt352 - fills out the supplied
int (*set_frequency)(struct dvb_frontend *fe, u32 frequency); * buffer with what to write.
int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); *
* Don't use on newer drivers.
*/
int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len);
/* /*
* These are provided separately from set_params in order to facilitate silicon * These are provided separately from set_params in order to
* tuners which require sophisticated tuning loops, controlling each parameter separately. * facilitate silicon tuners which require sophisticated tuning loops,
* controlling each parameter separately.
*
* Don't use on newer drivers.
*/ */
int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state); int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state); int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
}; };
/**
* struct analog_demod_info - Information struct for analog TV part of the demod
*
* @name: Name of the analog TV demodulator
*/
struct analog_demod_info { struct analog_demod_info {
char *name; char *name;
}; };
/**
* struct analog_demod_ops - Demodulation information and callbacks for
* analog TV and radio
*
* @info: pointer to struct analog_demod_info
* @set_params: callback function used to inform the demod to set the
* demodulator parameters needed to decode an analog or
* radio channel. The properties are passed via
* struct @analog_params;.
* @has_signal: returns 0xffff if has signal, or 0 if it doesn't.
* @get_afc: Used only by analog TV core. Reports the frequency
* drift due to AFC.
* @tuner_status: callback function that returns tuner status bits, e. g.
* TUNER_STATUS_LOCKED and TUNER_STATUS_STEREO.
* @standby: set the tuner to standby mode.
* @release: callback function called when frontend is dettached.
* drivers should free any allocated memory.
* @i2c_gate_ctrl: controls the I2C gate. Newer drivers should use I2C
* mux support instead.
* @set_config: callback function used to send some tuner-specific
* parameters.
*/
struct analog_demod_ops { struct analog_demod_ops {
struct analog_demod_info info; struct analog_demod_info info;
@ -263,12 +321,103 @@ struct analog_demod_ops {
struct dtv_frontend_properties; struct dtv_frontend_properties;
/**
* struct dvb_frontend_ops - Demodulation information and callbacks for
* ditialt TV
*
* @info: embedded struct dvb_tuner_info with tuner properties
* @delsys: Delivery systems supported by the frontend
* @detach: callback function called when frontend is detached.
* drivers should clean up, but not yet free the struct
* dvb_frontend allocation.
* @release: callback function called when frontend is ready to be
* freed.
* drivers should free any allocated memory.
* @release_sec: callback function requesting that the Satelite Equipment
* Control (SEC) driver to release and free any memory
* allocated by the driver.
* @init: callback function used to initialize the tuner device.
* @sleep: callback function used to put the tuner to sleep.
* @write: callback function used by some demod legacy drivers to
* allow other drivers to write data into their registers.
* Should not be used on new drivers.
* @tune: callback function used by demod drivers that use
* @DVBFE_ALGO_HW; to tune into a frequency.
* @get_frontend_algo: returns the desired hardware algorithm.
* @set_frontend: callback function used to inform the demod to set the
* parameters for demodulating a digital TV channel.
* The properties to be used are stored at
* @dvb_frontend.dtv_property_cache;. The demod can change
* the parameters to reflect the changes needed for the
* channel to be decoded, and update statistics.
* @get_tune_settings: callback function
* @get_frontend: callback function used to inform the parameters
* actuall in use. The properties to be used are stored at
* @dvb_frontend.dtv_property_cache; and update
* statistics. Please notice that it should not return
* an error code if the statistics are not available
* because the demog is not locked.
* @read_status: returns the locking status of the frontend.
* @read_ber: legacy callback function to return the bit error rate.
* Newer drivers should provide such info via DVBv5 API,
* e. g. @set_frontend;/@get_frontend;, implementing this
* callback only if DVBv3 API compatibility is wanted.
* @read_signal_strength: legacy callback function to return the signal
* strength. Newer drivers should provide such info via
* DVBv5 API, e. g. @set_frontend;/@get_frontend;,
* implementing this callback only if DVBv3 API
* compatibility is wanted.
* @read_snr: legacy callback function to return the Signal/Noise
* rate. Newer drivers should provide such info via
* DVBv5 API, e. g. @set_frontend;/@get_frontend;,
* implementing this callback only if DVBv3 API
* compatibility is wanted.
* @read_ucblocks: legacy callback function to return the Uncorrected Error
* Blocks. Newer drivers should provide such info via
* DVBv5 API, e. g. @set_frontend;/@get_frontend;,
* implementing this callback only if DVBv3 API
* compatibility is wanted.
* @diseqc_reset_overload: callback function to implement the
* FE_DISEQC_RESET_OVERLOAD ioctl (only Satellite)
* @diseqc_send_master_cmd: callback function to implement the
* FE_DISEQC_SEND_MASTER_CMD ioctl (only Satellite).
* @diseqc_recv_slave_reply: callback function to implement the
* FE_DISEQC_RECV_SLAVE_REPLY ioctl (only Satellite)
* @diseqc_send_burst: callback function to implement the
* FE_DISEQC_SEND_BURST ioctl (only Satellite).
* @set_tone: callback function to implement the
* FE_SET_TONE ioctl (only Satellite).
* @set_voltage: callback function to implement the
* FE_SET_VOLTAGE ioctl (only Satellite).
* @enable_high_lnb_voltage: callback function to implement the
* FE_ENABLE_HIGH_LNB_VOLTAGE ioctl (only Satellite).
* @dishnetwork_send_legacy_command: callback function to implement the
* FE_DISHNETWORK_SEND_LEGACY_CMD ioctl (only Satellite).
* Drivers should not use this, except when the DVB
* core emulation fails to provide proper support (e.g.
* if @set_voltage takes more than 8ms to work), and
* when backward compatibility with this legacy API is
* required.
* @i2c_gate_ctrl: controls the I2C gate. Newer drivers should use I2C
* mux support instead.
* @ts_bus_ctrl: callback function used to take control of the TS bus.
* @set_lna: callback function to power on/off/auto the LNA.
* @search: callback function used on some custom algo search algos.
* @tuner_ops: pointer to struct dvb_tuner_ops
* @analog_ops: pointer to struct analog_demod_ops
* @set_property: callback function to allow the frontend to validade
* incoming properties. Should not be used on new drivers.
* @get_property: callback function to allow the frontend to override
* outcoming properties. Should not be used on new drivers.
*/
struct dvb_frontend_ops { struct dvb_frontend_ops {
struct dvb_frontend_info info; struct dvb_frontend_info info;
u8 delsys[MAX_DELSYS]; u8 delsys[MAX_DELSYS];
void (*detach)(struct dvb_frontend *fe);
void (*release)(struct dvb_frontend* fe); void (*release)(struct dvb_frontend* fe);
void (*release_sec)(struct dvb_frontend* fe); void (*release_sec)(struct dvb_frontend* fe);
@ -282,7 +431,8 @@ struct dvb_frontend_ops {
bool re_tune, bool re_tune,
unsigned int mode_flags, unsigned int mode_flags,
unsigned int *delay, unsigned int *delay,
fe_status_t *status); enum fe_status *status);
/* get frontend tuning algorithm from the module */ /* get frontend tuning algorithm from the module */
enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe); enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
@ -290,9 +440,10 @@ struct dvb_frontend_ops {
int (*set_frontend)(struct dvb_frontend *fe); int (*set_frontend)(struct dvb_frontend *fe);
int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings); int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
int (*get_frontend)(struct dvb_frontend *fe); int (*get_frontend)(struct dvb_frontend *fe,
struct dtv_frontend_properties *props);
int (*read_status)(struct dvb_frontend* fe, fe_status_t* status); int (*read_status)(struct dvb_frontend *fe, enum fe_status *status);
int (*read_ber)(struct dvb_frontend* fe, u32* ber); int (*read_ber)(struct dvb_frontend* fe, u32* ber);
int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength); int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
int (*read_snr)(struct dvb_frontend* fe, u16* snr); int (*read_snr)(struct dvb_frontend* fe, u16* snr);
@ -301,9 +452,11 @@ struct dvb_frontend_ops {
int (*diseqc_reset_overload)(struct dvb_frontend* fe); int (*diseqc_reset_overload)(struct dvb_frontend* fe);
int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd); int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply); int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply);
int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); int (*diseqc_send_burst)(struct dvb_frontend *fe,
int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); enum fe_sec_mini_cmd minicmd);
int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); int (*set_tone)(struct dvb_frontend *fe, enum fe_sec_tone_mode tone);
int (*set_voltage)(struct dvb_frontend *fe,
enum fe_sec_voltage voltage);
int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg); int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable); int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
@ -311,7 +464,8 @@ struct dvb_frontend_ops {
int (*set_lna)(struct dvb_frontend *); int (*set_lna)(struct dvb_frontend *);
int (*set_input)(struct dvb_frontend *, int); int (*set_input)(struct dvb_frontend *, int);
/* These callbacks are for devices that implement their own /*
* These callbacks are for devices that implement their own
* tuning algorithms, rather than a simple swzigzag * tuning algorithms, rather than a simple swzigzag
*/ */
enum dvbfe_search (*search)(struct dvb_frontend *fe); enum dvbfe_search (*search)(struct dvb_frontend *fe);
@ -328,6 +482,7 @@ struct dvb_frontend_ops {
#ifdef __DVB_CORE__ #ifdef __DVB_CORE__
#define MAX_EVENT 8 #define MAX_EVENT 8
/* Used only internally at dvb_frontend.c */
struct dvb_fe_events { struct dvb_fe_events {
struct dvb_frontend_event events[MAX_EVENT]; struct dvb_frontend_event events[MAX_EVENT];
int eventw; int eventw;
@ -338,30 +493,100 @@ struct dvb_fe_events {
}; };
#endif #endif
/**
* struct dtv_frontend_properties - contains a list of properties that are
* specific to a digital TV standard.
*
* @frequency: frequency in Hz for terrestrial/cable or in kHz for
* Satellite
* @modulation: Frontend modulation type
* @voltage: SEC voltage (only Satellite)
* @sectone: SEC tone mode (only Satellite)
* @inversion: Spectral inversion
* @fec_inner: Forward error correction inner Code Rate
* @transmission_mode: Transmission Mode
* @bandwidth_hz: Bandwidth, in Hz. A zero value means that userspace
* wants to autodetect.
* @guard_interval: Guard Interval
* @hierarchy: Hierarchy
* @symbol_rate: Symbol Rate
* @code_rate_HP: high priority stream code rate
* @code_rate_LP: low priority stream code rate
* @pilot: Enable/disable/autodetect pilot tones
* @rolloff: Rolloff factor (alpha)
* @delivery_system: FE delivery system (e. g. digital TV standard)
* @interleaving: interleaving
* @isdbt_partial_reception: ISDB-T partial reception (only ISDB standard)
* @isdbt_sb_mode: ISDB-T Sound Broadcast (SB) mode (only ISDB standard)
* @isdbt_sb_subchannel: ISDB-T SB subchannel (only ISDB standard)
* @isdbt_sb_segment_idx: ISDB-T SB segment index (only ISDB standard)
* @isdbt_sb_segment_count: ISDB-T SB segment count (only ISDB standard)
* @isdbt_layer_enabled: ISDB Layer enabled (only ISDB standard)
* @layer: ISDB per-layer data (only ISDB standard)
* @layer.segment_count: Segment Count;
* @layer.fec: per layer code rate;
* @layer.modulation: per layer modulation;
* @layer.interleaving: per layer interleaving.
* @stream_id: If different than zero, enable substream filtering, if
* hardware supports (DVB-S2 and DVB-T2).
* @atscmh_fic_ver: Version number of the FIC (Fast Information Channel)
* signaling data (only ATSC-M/H)
* @atscmh_parade_id: Parade identification number (only ATSC-M/H)
* @atscmh_nog: Number of MH groups per MH subframe for a designated
* parade (only ATSC-M/H)
* @atscmh_tnog: Total number of MH groups including all MH groups
* belonging to all MH parades in one MH subframe
* (only ATSC-M/H)
* @atscmh_sgn: Start group number (only ATSC-M/H)
* @atscmh_prc: Parade repetition cycle (only ATSC-M/H)
* @atscmh_rs_frame_mode: Reed Solomon (RS) frame mode (only ATSC-M/H)
* @atscmh_rs_frame_ensemble: RS frame ensemble (only ATSC-M/H)
* @atscmh_rs_code_mode_pri: RS code mode pri (only ATSC-M/H)
* @atscmh_rs_code_mode_sec: RS code mode sec (only ATSC-M/H)
* @atscmh_sccc_block_mode: Series Concatenated Convolutional Code (SCCC)
* Block Mode (only ATSC-M/H)
* @atscmh_sccc_code_mode_a: SCCC code mode A (only ATSC-M/H)
* @atscmh_sccc_code_mode_b: SCCC code mode B (only ATSC-M/H)
* @atscmh_sccc_code_mode_c: SCCC code mode C (only ATSC-M/H)
* @atscmh_sccc_code_mode_d: SCCC code mode D (only ATSC-M/H)
* @lna: Power ON/OFF/AUTO the Linear Now-noise Amplifier (LNA)
* @strength: DVBv5 API statistics: Signal Strength
* @cnr: DVBv5 API statistics: Signal to Noise ratio of the
* (main) carrier
* @pre_bit_error: DVBv5 API statistics: pre-Viterbi bit error count
* @pre_bit_count: DVBv5 API statistics: pre-Viterbi bit count
* @post_bit_error: DVBv5 API statistics: post-Viterbi bit error count
* @post_bit_count: DVBv5 API statistics: post-Viterbi bit count
* @block_error: DVBv5 API statistics: block error count
* @block_count: DVBv5 API statistics: block count
*
* NOTE: derivated statistics like Uncorrected Error blocks (UCE) are
* calculated on userspace.
*
* Only a subset of the properties are needed for a given delivery system.
* For more info, consult the media_api.html with the documentation of the
* Userspace API.
*/
struct dtv_frontend_properties { struct dtv_frontend_properties {
/* Cache State */
u32 state;
u32 frequency; u32 frequency;
fe_modulation_t modulation; enum fe_modulation modulation;
fe_sec_voltage_t voltage; enum fe_sec_voltage voltage;
fe_sec_tone_mode_t sectone; enum fe_sec_tone_mode sectone;
fe_spectral_inversion_t inversion; enum fe_spectral_inversion inversion;
fe_code_rate_t fec_inner; enum fe_code_rate fec_inner;
fe_transmit_mode_t transmission_mode; enum fe_transmit_mode transmission_mode;
u32 bandwidth_hz; /* 0 = AUTO */ u32 bandwidth_hz; /* 0 = AUTO */
fe_guard_interval_t guard_interval; enum fe_guard_interval guard_interval;
fe_hierarchy_t hierarchy; enum fe_hierarchy hierarchy;
u32 symbol_rate; u32 symbol_rate;
fe_code_rate_t code_rate_HP; enum fe_code_rate code_rate_HP;
fe_code_rate_t code_rate_LP; enum fe_code_rate code_rate_LP;
fe_pilot_t pilot; enum fe_pilot pilot;
fe_rolloff_t rolloff; enum fe_rolloff rolloff;
fe_delivery_system_t delivery_system; enum fe_delivery_system delivery_system;
enum fe_interleaving interleaving; enum fe_interleaving interleaving;
@ -374,8 +599,8 @@ struct dtv_frontend_properties {
u8 isdbt_layer_enabled; u8 isdbt_layer_enabled;
struct { struct {
u8 segment_count; u8 segment_count;
fe_code_rate_t fec; enum fe_code_rate fec;
fe_modulation_t modulation; enum fe_modulation modulation;
u8 interleaving; u8 interleaving;
} layer[3]; } layer[3];
@ -413,9 +638,41 @@ struct dtv_frontend_properties {
struct dtv_fe_stats post_bit_count; struct dtv_fe_stats post_bit_count;
struct dtv_fe_stats block_error; struct dtv_fe_stats block_error;
struct dtv_fe_stats block_count; struct dtv_fe_stats block_count;
/* private: */
/* Cache State */
u32 state;
}; };
#define DVB_FE_NO_EXIT 0
#define DVB_FE_NORMAL_EXIT 1
#define DVB_FE_DEVICE_REMOVED 2
#define DVB_FE_DEVICE_RESUME 3
/**
* struct dvb_frontend - Frontend structure to be used on drivers.
*
* @refcount: refcount to keep track of struct dvb_frontend
* references
* @ops: embedded struct dvb_frontend_ops
* @dvb: pointer to struct dvb_adapter
* @demodulator_priv: demod private data
* @tuner_priv: tuner private data
* @frontend_priv: frontend private data
* @sec_priv: SEC private data
* @analog_demod_priv: Analog demod private data
* @dtv_property_cache: embedded struct dtv_frontend_properties
* @callback: callback function used on some drivers to call
* either the tuner or the demodulator.
* @id: Frontend ID
* @exit: Used to inform the DVB core that the frontend
* thread should exit (usually, means that the hardware
* got disconnected.
*/
struct dvb_frontend { struct dvb_frontend {
struct kref refcount;
struct dvb_frontend_ops ops; struct dvb_frontend_ops ops;
struct dvb_adapter *dvb; struct dvb_adapter *dvb;
void *demodulator_priv; void *demodulator_priv;
@ -428,20 +685,129 @@ struct dvb_frontend {
#define DVB_FRONTEND_COMPONENT_DEMOD 1 #define DVB_FRONTEND_COMPONENT_DEMOD 1
int (*callback)(void *adapter_priv, int component, int cmd, int arg); int (*callback)(void *adapter_priv, int component, int cmd, int arg);
int id; int id;
unsigned int exit;
}; };
extern int dvb_register_frontend(struct dvb_adapter *dvb, /**
* dvb_register_frontend() - Registers a DVB frontend at the adapter
*
* @dvb: pointer to the dvb adapter
* @fe: pointer to the frontend struct
*
* Allocate and initialize the private data needed by the frontend core to
* manage the frontend and calls dvb_register_device() to register a new
* frontend. It also cleans the property cache that stores the frontend
* parameters and selects the first available delivery system.
*/
int dvb_register_frontend(struct dvb_adapter *dvb,
struct dvb_frontend *fe); struct dvb_frontend *fe);
extern int dvb_unregister_frontend(struct dvb_frontend *fe); /**
* dvb_unregister_frontend() - Unregisters a DVB frontend
*
* @fe: pointer to the frontend struct
*
* Stops the frontend kthread, calls dvb_unregister_device() and frees the
* private frontend data allocated by dvb_register_frontend().
*
* NOTE: This function doesn't frees the memory allocated by the demod,
* by the SEC driver and by the tuner. In order to free it, an explicit call to
* dvb_frontend_detach() is needed, after calling this function.
*/
int dvb_unregister_frontend(struct dvb_frontend *fe);
extern void dvb_frontend_detach(struct dvb_frontend *fe); /**
* dvb_frontend_detach() - Detaches and frees frontend specific data
*
* @fe: pointer to the frontend struct
*
* This function should be called after dvb_unregister_frontend(). It
* calls the SEC, tuner and demod release functions:
* &dvb_frontend_ops.release_sec, &dvb_frontend_ops.tuner_ops.release,
* &dvb_frontend_ops.analog_ops.release and &dvb_frontend_ops.release.
*
* If the driver is compiled with CONFIG_MEDIA_ATTACH, it also decreases
* the module reference count, needed to allow userspace to remove the
* previously used DVB frontend modules.
*/
void dvb_frontend_detach(struct dvb_frontend *fe);
extern void dvb_frontend_reinitialise(struct dvb_frontend *fe); /**
extern int dvb_frontend_suspend(struct dvb_frontend *fe); * dvb_frontend_suspend() - Suspends a Digital TV frontend
extern int dvb_frontend_resume(struct dvb_frontend *fe); *
* @fe: pointer to the frontend struct
*
* This function prepares a Digital TV frontend to suspend.
*
* In order to prepare the tuner to suspend, if
* &dvb_frontend_ops.tuner_ops.suspend\(\) is available, it calls it. Otherwise,
* it will call &dvb_frontend_ops.tuner_ops.sleep\(\), if available.
*
* It will also call &dvb_frontend_ops.sleep\(\) to put the demod to suspend.
*
* The drivers should also call dvb_frontend_suspend\(\) as part of their
* handler for the &device_driver.suspend\(\).
*/
int dvb_frontend_suspend(struct dvb_frontend *fe);
extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec); /**
extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime); * dvb_frontend_resume() - Resumes a Digital TV frontend
*
* @fe: pointer to the frontend struct
*
* This function resumes the usual operation of the tuner after resume.
*
* In order to resume the frontend, it calls the demod &dvb_frontend_ops.init\(\).
*
* If &dvb_frontend_ops.tuner_ops.resume\(\) is available, It, it calls it.
* Otherwise,t will call &dvb_frontend_ops.tuner_ops.init\(\), if available.
*
* Once tuner and demods are resumed, it will enforce that the SEC voltage and
* tone are restored to their previous values and wake up the frontend's
* kthread in order to retune the frontend.
*
* The drivers should also call dvb_frontend_resume() as part of their
* handler for the &device_driver.resume\(\).
*/
int dvb_frontend_resume(struct dvb_frontend *fe);
/**
* dvb_frontend_reinitialise() - forces a reinitialisation at the frontend
*
* @fe: pointer to the frontend struct
*
* Calls &dvb_frontend_ops.init\(\) and &dvb_frontend_ops.tuner_ops.init\(\),
* and resets SEC tone and voltage (for Satellite systems).
*
* NOTE: Currently, this function is used only by one driver (budget-av).
* It seems to be due to address some special issue with that specific
* frontend.
*/
void dvb_frontend_reinitialise(struct dvb_frontend *fe);
/**
* dvb_frontend_sleep_until() - Sleep for the amount of time given by
* add_usec parameter
*
* @waketime: pointer to a struct ktime_t
* @add_usec: time to sleep, in microseconds
*
* This function is used to measure the time required for the
* %FE_DISHNETWORK_SEND_LEGACY_CMD ioctl to work. It needs to be as precise
* as possible, as it affects the detection of the dish tone command at the
* satellite subsystem.
*
* Its used internally by the DVB frontend core, in order to emulate
* %FE_DISHNETWORK_SEND_LEGACY_CMD using the &dvb_frontend_ops.set_voltage\(\)
* callback.
*
* NOTE: it should not be used at the drivers, as the emulation for the
* legacy callback is provided by the Kernel. The only situation where this
* should be at the drivers is when there are some bugs at the hardware that
* would prevent the core emulation to work. On such cases, the driver would
* be writing a &dvb_frontend_ops.dishnetwork_send_legacy_command\(\) and
* calling this function directly.
*/
void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec);
#endif #endif

View File

@ -13,10 +13,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/bitops.h> #include <linux/bitops.h>

View File

@ -13,10 +13,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#ifndef __DVB_MATH_H #ifndef __DVB_MATH_H
@ -25,33 +21,45 @@
#include <linux/types.h> #include <linux/types.h>
/** /**
* computes log2 of a value; the result is shifted left by 24 bits * intlog2 - computes log2 of a value; the result is shifted left by 24 bits
*
* @value: The value (must be != 0)
* *
* to use rational values you can use the following method: * to use rational values you can use the following method:
*
* intlog2(value) = intlog2(value * 2^x) - x * 2^24 * intlog2(value) = intlog2(value * 2^x) - x * 2^24
* *
* example: intlog2(8) will give 3 << 24 = 3 * 2^24 * Some usecase examples:
* example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
* example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
* *
* @param value The value (must be != 0) * intlog2(8) will give 3 << 24 = 3 * 2^24
* @return log2(value) * 2^24 *
* intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
*
* intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
*
*
* return: log2(value) * 2^24
*/ */
extern unsigned int intlog2(u32 value); extern unsigned int intlog2(u32 value);
/** /**
* computes log10 of a value; the result is shifted left by 24 bits * intlog10 - computes log10 of a value; the result is shifted left by 24 bits
*
* @value: The value (must be != 0)
* *
* to use rational values you can use the following method: * to use rational values you can use the following method:
*
* intlog10(value) = intlog10(value * 10^x) - x * 2^24 * intlog10(value) = intlog10(value * 10^x) - x * 2^24
* *
* example: intlog10(1000) will give 3 << 24 = 3 * 2^24 * An usecase example:
*
* intlog10(1000) will give 3 << 24 = 3 * 2^24
*
* due to the implementation intlog10(1000) might be not exactly 3 * 2^24 * due to the implementation intlog10(1000) might be not exactly 3 * 2^24
* *
* look at intlog2 for similar examples * look at intlog2 for similar examples
* *
* @param value The value (must be != 0) * return: log10(value) * 2^24
* @return log10(value) * 2^24
*/ */
extern unsigned int intlog10(u32 value); extern unsigned int intlog10(u32 value);

File diff suppressed because it is too large Load Diff

View File

@ -13,10 +13,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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 _DVB_NET_H_ #ifndef _DVB_NET_H_

View File

@ -241,7 +241,7 @@ int dvb_netstream_init(struct dvb_adapter *dvb_adapter,
spin_lock_init(&ns->lock); spin_lock_init(&ns->lock);
ns->exit = 0; ns->exit = 0;
dvb_register_device(dvb_adapter, &ns->dvbdev, &ns_dev, ns, dvb_register_device(dvb_adapter, &ns->dvbdev, &ns_dev, ns,
DVB_DEVICE_NS); DVB_DEVICE_NS, 0);
INIT_LIST_HEAD(&ns->nssl); INIT_LIST_HEAD(&ns->nssl);
return 0; return 0;
} }

View File

@ -18,10 +18,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser 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.
*/ */
@ -60,7 +56,13 @@ void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf) int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
{ {
return (rbuf->pread==rbuf->pwrite); /* smp_load_acquire() to load write pointer on reader side
* this pairs with smp_store_release() in dvb_ringbuffer_write(),
* dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset()
*
* for memory barriers also see Documentation/circular-buffers.txt
*/
return (rbuf->pread == smp_load_acquire(&rbuf->pwrite));
} }
@ -69,7 +71,12 @@ ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf)
{ {
ssize_t free; ssize_t free;
free = rbuf->pread - rbuf->pwrite; /* ACCESS_ONCE() to load read pointer on writer side
* this pairs with smp_store_release() in dvb_ringbuffer_read(),
* dvb_ringbuffer_read_user(), dvb_ringbuffer_flush(),
* or dvb_ringbuffer_reset()
*/
free = ACCESS_ONCE(rbuf->pread) - rbuf->pwrite;
if (free <= 0) if (free <= 0)
free += rbuf->size; free += rbuf->size;
return free-1; return free-1;
@ -81,7 +88,11 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
{ {
ssize_t avail; ssize_t avail;
avail = rbuf->pwrite - rbuf->pread; /* smp_load_acquire() to load write pointer on reader side
* this pairs with smp_store_release() in dvb_ringbuffer_write(),
* dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset()
*/
avail = smp_load_acquire(&rbuf->pwrite) - rbuf->pread;
if (avail < 0) if (avail < 0)
avail += rbuf->size; avail += rbuf->size;
return avail; return avail;
@ -91,14 +102,25 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf) void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
{ {
rbuf->pread = rbuf->pwrite; /* dvb_ringbuffer_flush() counts as read operation
* smp_load_acquire() to load write pointer
* smp_store_release() to update read pointer, this ensures that the
* correct pointer is visible for subsequent dvb_ringbuffer_free()
* calls on other cpu cores
*/
smp_store_release(&rbuf->pread, smp_load_acquire(&rbuf->pwrite));
rbuf->error = 0; rbuf->error = 0;
} }
EXPORT_SYMBOL(dvb_ringbuffer_flush); EXPORT_SYMBOL(dvb_ringbuffer_flush);
void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf) void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf)
{ {
rbuf->pread = rbuf->pwrite = 0; /* dvb_ringbuffer_reset() counts as read and write operation
* smp_store_release() to update read pointer
*/
smp_store_release(&rbuf->pread, 0);
/* smp_store_release() to update write pointer */
smp_store_release(&rbuf->pwrite, 0);
rbuf->error = 0; rbuf->error = 0;
} }
@ -124,12 +146,17 @@ ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, si
return -EFAULT; return -EFAULT;
buf += split; buf += split;
todo -= split; todo -= split;
rbuf->pread = 0; /* smp_store_release() for read pointer update to ensure
* that buf is not overwritten until read is complete,
* this pairs with ACCESS_ONCE() in dvb_ringbuffer_free()
*/
smp_store_release(&rbuf->pread, 0);
} }
if (copy_to_user(buf, rbuf->data+rbuf->pread, todo)) if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
return -EFAULT; return -EFAULT;
rbuf->pread = (rbuf->pread + todo) % rbuf->size; /* smp_store_release() to update read pointer, see above */
smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size);
return len; return len;
} }
@ -144,11 +171,16 @@ void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
memcpy(buf, rbuf->data+rbuf->pread, split); memcpy(buf, rbuf->data+rbuf->pread, split);
buf += split; buf += split;
todo -= split; todo -= split;
rbuf->pread = 0; /* smp_store_release() for read pointer update to ensure
* that buf is not overwritten until read is complete,
* this pairs with ACCESS_ONCE() in dvb_ringbuffer_free()
*/
smp_store_release(&rbuf->pread, 0);
} }
memcpy(buf, rbuf->data+rbuf->pread, todo); memcpy(buf, rbuf->data+rbuf->pread, todo);
rbuf->pread = (rbuf->pread + todo) % rbuf->size; /* smp_store_release() to update read pointer, see above */
smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size);
} }
@ -163,10 +195,47 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t
memcpy(rbuf->data+rbuf->pwrite, buf, split); memcpy(rbuf->data+rbuf->pwrite, buf, split);
buf += split; buf += split;
todo -= split; todo -= split;
rbuf->pwrite = 0; /* smp_store_release() for write pointer update to ensure that
* written data is visible on other cpu cores before the pointer
* update, this pairs with smp_load_acquire() in
* dvb_ringbuffer_empty() or dvb_ringbuffer_avail()
*/
smp_store_release(&rbuf->pwrite, 0);
} }
memcpy(rbuf->data+rbuf->pwrite, buf, todo); memcpy(rbuf->data+rbuf->pwrite, buf, todo);
rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size; /* smp_store_release() for write pointer update, see above */
smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size);
return len;
}
ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
const u8 __user *buf, size_t len)
{
int status;
size_t todo = len;
size_t split;
split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
if (split > 0) {
status = copy_from_user(rbuf->data+rbuf->pwrite, buf, split);
if (status)
return len - todo;
buf += split;
todo -= split;
/* smp_store_release() for write pointer update to ensure that
* written data is visible on other cpu cores before the pointer
* update, this pairs with smp_load_acquire() in
* dvb_ringbuffer_empty() or dvb_ringbuffer_avail()
*/
smp_store_release(&rbuf->pwrite, 0);
}
status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo);
if (status)
return len - todo;
/* smp_store_release() for write pointer update, see above */
smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size);
return len; return len;
} }
@ -302,3 +371,4 @@ EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
EXPORT_SYMBOL(dvb_ringbuffer_read_user); EXPORT_SYMBOL(dvb_ringbuffer_read_user);
EXPORT_SYMBOL(dvb_ringbuffer_read); EXPORT_SYMBOL(dvb_ringbuffer_read);
EXPORT_SYMBOL(dvb_ringbuffer_write); EXPORT_SYMBOL(dvb_ringbuffer_write);
EXPORT_SYMBOL(dvb_ringbuffer_write_user);

View File

@ -18,10 +18,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser 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 _DVB_RINGBUFFER_H_ #ifndef _DVB_RINGBUFFER_H_
@ -30,6 +26,18 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/wait.h> #include <linux/wait.h>
/**
* struct dvb_ringbuffer - Describes a ring buffer used at DVB framework
*
* @data: Area were the ringbuffer data is written
* @size: size of the ringbuffer
* @pread: next position to read
* @pwrite: next position to write
* @error: used by ringbuffer clients to indicate that an error happened.
* @queue: Wait queue used by ringbuffer clients to indicate when buffer
* was filled
* @lock: Spinlock used to protect the ringbuffer
*/
struct dvb_ringbuffer { struct dvb_ringbuffer {
u8 *data; u8 *data;
ssize_t size; ssize_t size;
@ -43,144 +51,230 @@ struct dvb_ringbuffer {
#define DVB_RINGBUFFER_PKTHDRSIZE 3 #define DVB_RINGBUFFER_PKTHDRSIZE 3
/**
/* * dvb_ringbuffer_init - initialize ring buffer, lock and queue
** Notes: *
** ------ * @rbuf: pointer to struct dvb_ringbuffer
** (1) For performance reasons read and write routines don't check buffer sizes * @data: pointer to the buffer where the data will be stored
** and/or number of bytes free/available. This has to be done before these * @len: bytes from ring buffer into @buf
** routines are called. For example:
**
** *** write <buflen> bytes ***
** free = dvb_ringbuffer_free(rbuf);
** if (free >= buflen)
** count = dvb_ringbuffer_write(rbuf, buffer, buflen);
** else
** ...
**
** *** read min. 1000, max. <bufsize> bytes ***
** avail = dvb_ringbuffer_avail(rbuf);
** if (avail >= 1000)
** count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
** else
** ...
**
** (2) If there is exactly one reader and one writer, there is no need
** to lock read or write operations.
** Two or more readers must be locked against each other.
** Flushing the buffer counts as a read operation.
** Resetting the buffer counts as a read and write operation.
** Two or more writers must be locked against each other.
*/ */
extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data,
size_t len);
/* initialize ring buffer, lock and queue */ /**
extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len); * dvb_ringbuffer_empty - test whether buffer is empty
*
/* test whether buffer is empty */ * @rbuf: pointer to struct dvb_ringbuffer
*/
extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf); extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf);
/* return the number of free bytes in the buffer */ /**
* dvb_ringbuffer_free - returns the number of free bytes in the buffer
*
* @rbuf: pointer to struct dvb_ringbuffer
*
* Return: number of free bytes in the buffer
*/
extern ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf); extern ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf);
/* return the number of bytes waiting in the buffer */ /**
* dvb_ringbuffer_avail - returns the number of bytes waiting in the buffer
*
* @rbuf: pointer to struct dvb_ringbuffer
*
* Return: number of bytes waiting in the buffer
*/
extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf); extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf);
/**
/* * dvb_ringbuffer_reset - resets the ringbuffer to initial state
** Reset the read and write pointers to zero and flush the buffer *
** This counts as a read and write operation * @rbuf: pointer to struct dvb_ringbuffer
*
* Resets the read and write pointers to zero and flush the buffer.
*
* This counts as a read and write operation
*/ */
extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf); extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf);
/*
* read routines & macros
*/
/* read routines & macros */ /**
/* ---------------------- */ * dvb_ringbuffer_flush - flush buffer
/* flush buffer */ *
* @rbuf: pointer to struct dvb_ringbuffer
*/
extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf); extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf);
/* flush buffer protected by spinlock and wake-up waiting task(s) */ /**
* dvb_ringbuffer_flush_spinlock_wakeup- flush buffer protected by spinlock
* and wake-up waiting task(s)
*
* @rbuf: pointer to struct dvb_ringbuffer
*/
extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf); extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
/* peek at byte <offs> in the buffer */ /**
* DVB_RINGBUFFER_PEEK - peek at byte @offs in the buffer
*
* @rbuf: pointer to struct dvb_ringbuffer
* @offs: offset inside the ringbuffer
*/
#define DVB_RINGBUFFER_PEEK(rbuf, offs) \ #define DVB_RINGBUFFER_PEEK(rbuf, offs) \
(rbuf)->data[((rbuf)->pread+(offs))%(rbuf)->size] ((rbuf)->data[((rbuf)->pread + (offs)) % (rbuf)->size])
/* advance read ptr by <num> bytes */ /**
#define DVB_RINGBUFFER_SKIP(rbuf,num) \ * DVB_RINGBUFFER_SKIP - advance read ptr by @num bytes
(rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size *
* @rbuf: pointer to struct dvb_ringbuffer
* @num: number of bytes to advance
*/
#define DVB_RINGBUFFER_SKIP(rbuf, num) {\
(rbuf)->pread = ((rbuf)->pread + (num)) % (rbuf)->size;\
}
/* /**
** read <len> bytes from ring buffer into <buf> * dvb_ringbuffer_read_user - Reads a buffer into a user pointer
** <usermem> specifies whether <buf> resides in user space *
** returns number of bytes transferred or -EFAULT * @rbuf: pointer to struct dvb_ringbuffer
* @buf: pointer to the buffer where the data will be stored
* @len: bytes from ring buffer into @buf
*
* This variant assumes that the buffer is a memory at the userspace. So,
* it will internally call copy_to_user().
*
* Return: number of bytes transferred or -EFAULT
*/ */
extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf,
u8 __user *buf, size_t len); u8 __user *buf, size_t len);
/**
* dvb_ringbuffer_read - Reads a buffer into a pointer
*
* @rbuf: pointer to struct dvb_ringbuffer
* @buf: pointer to the buffer where the data will be stored
* @len: bytes from ring buffer into @buf
*
* This variant assumes that the buffer is a memory at the Kernel space
*
* Return: number of bytes transferred or -EFAULT
*/
extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
u8 *buf, size_t len); u8 *buf, size_t len);
/*
* write routines & macros
*/
/* write routines & macros */ /**
/* ----------------------- */ * DVB_RINGBUFFER_WRITE_BYTE - write single byte to ring buffer
/* write single byte to ring buffer */ *
* @rbuf: pointer to struct dvb_ringbuffer
* @byte: byte to write
*/
#define DVB_RINGBUFFER_WRITE_BYTE(rbuf, byte) \ #define DVB_RINGBUFFER_WRITE_BYTE(rbuf, byte) \
{ (rbuf)->data[(rbuf)->pwrite] = (byte); \ { (rbuf)->data[(rbuf)->pwrite] = (byte); \
(rbuf)->pwrite = ((rbuf)->pwrite + 1) % (rbuf)->size; } (rbuf)->pwrite = ((rbuf)->pwrite + 1) % (rbuf)->size; }
/*
** write <len> bytes to ring buffer /**
** <usermem> specifies whether <buf> resides in user space * dvb_ringbuffer_write - Writes a buffer into the ringbuffer
** returns number of bytes transferred or -EFAULT *
* @rbuf: pointer to struct dvb_ringbuffer
* @buf: pointer to the buffer where the data will be read
* @len: bytes from ring buffer into @buf
*
* This variant assumes that the buffer is a memory at the Kernel space
*
* return: number of bytes transferred or -EFAULT
*/ */
extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
size_t len); size_t len);
/**
* dvb_ringbuffer_write_user - Writes a buffer received via a user pointer
*
* @rbuf: pointer to struct dvb_ringbuffer
* @buf: pointer to the buffer where the data will be read
* @len: bytes from ring buffer into @buf
*
* This variant assumes that the buffer is a memory at the userspace. So,
* it will internally call copy_from_user().
*
* Return: number of bytes transferred or -EFAULT
*/
extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
const u8 __user *buf, size_t len);
/** /**
* Write a packet into the ringbuffer. * dvb_ringbuffer_pkt_write - Write a packet into the ringbuffer.
* *
* <rbuf> Ringbuffer to write to. * @rbuf: Ringbuffer to write to.
* <buf> Buffer to write. * @buf: Buffer to write.
* <len> Length of buffer (currently limited to 65535 bytes max). * @len: Length of buffer (currently limited to 65535 bytes max).
* returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL. *
* Return: Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
*/ */
extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8 *buf, extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8 *buf,
size_t len); size_t len);
/** /**
* Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this * dvb_ringbuffer_pkt_read_user - Read from a packet in the ringbuffer.
* does NOT update the read pointer in the ringbuffer. You must use
* dvb_ringbuffer_pkt_dispose() to mark a packet as no longer required.
* *
* <rbuf> Ringbuffer concerned. * @rbuf: Ringbuffer concerned.
* <idx> Packet index as returned by dvb_ringbuffer_pkt_next(). * @idx: Packet index as returned by dvb_ringbuffer_pkt_next().
* <offset> Offset into packet to read from. * @offset: Offset into packet to read from.
* <buf> Destination buffer for data. * @buf: Destination buffer for data.
* <len> Size of destination buffer. * @len: Size of destination buffer.
* <usermem> Set to 1 if <buf> is in userspace. *
* returns Number of bytes read, or -EFAULT. * Return: Number of bytes read, or -EFAULT.
*
* .. note::
*
* unlike dvb_ringbuffer_read(), this does **NOT** update the read pointer
* in the ringbuffer. You must use dvb_ringbuffer_pkt_dispose() to mark a
* packet as no longer required.
*/
extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf,
size_t idx,
int offset, u8 __user *buf,
size_t len);
/**
* dvb_ringbuffer_pkt_read - Read from a packet in the ringbuffer.
* Note: unlike dvb_ringbuffer_read_user(), this DOES update the read pointer
* in the ringbuffer.
*
* @rbuf: Ringbuffer concerned.
* @idx: Packet index as returned by dvb_ringbuffer_pkt_next().
* @offset: Offset into packet to read from.
* @buf: Destination buffer for data.
* @len: Size of destination buffer.
*
* Return: Number of bytes read, or -EFAULT.
*/ */
extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
int offset, u8 __user *buf, size_t len);
extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
int offset, u8 *buf, size_t len); int offset, u8 *buf, size_t len);
/** /**
* Dispose of a packet in the ring buffer. * dvb_ringbuffer_pkt_dispose - Dispose of a packet in the ring buffer.
* *
* <rbuf> Ring buffer concerned. * @rbuf: Ring buffer concerned.
* <idx> Packet index as returned by dvb_ringbuffer_pkt_next(). * @idx: Packet index as returned by dvb_ringbuffer_pkt_next().
*/ */
extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx); extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx);
/** /**
* Get the index of the next packet in a ringbuffer. * dvb_ringbuffer_pkt_next - Get the index of the next packet in a ringbuffer.
* *
* <rbuf> Ringbuffer concerned. * @rbuf: Ringbuffer concerned.
* <idx> Previous packet index, or -1 to return the first packet index. * @idx: Previous packet index, or -1 to return the first packet index.
* <pktlen> On success, will be updated to contain the length of the packet in bytes. * @pktlen: On success, will be updated to contain the length of the packet
* in bytes.
* returns Packet index (if >=0), or -1 if no packets available. * returns Packet index (if >=0), or -1 if no packets available.
*/ */
extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen); extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf,
size_t idx, size_t *pktlen);
#endif /* _DVB_RINGBUFFER_H_ */ #endif /* _DVB_RINGBUFFER_H_ */

View File

@ -15,12 +15,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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.
*
*/ */
#define pr_fmt(fmt) "dvbdev: " fmt
#include <linux/types.h> #include <linux/types.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/string.h> #include <linux/string.h>
@ -35,13 +33,22 @@
#include <linux/version.h> #include <linux/version.h>
#include "dvbdev.h" #include "dvbdev.h"
#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,0,0))
/* Due to enum tuner_pad_index */
#include <media/tuner.h>
#endif
static DEFINE_MUTEX(dvbdev_mutex); static DEFINE_MUTEX(dvbdev_mutex);
static int dvbdev_debug; static int dvbdev_debug;
module_param(dvbdev_debug, int, 0644); module_param(dvbdev_debug, int, 0644);
MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off)."); MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off).");
#define dprintk if (dvbdev_debug) printk #define dprintk(fmt, arg...) do { \
if (dvbdev_debug) \
printk(KERN_DEBUG pr_fmt("%s: " fmt), \
__func__, ##arg); \
} while (0)
static LIST_HEAD(dvb_adapter_list); static LIST_HEAD(dvb_adapter_list);
static DEFINE_MUTEX(dvbdev_register_lock); static DEFINE_MUTEX(dvbdev_register_lock);
@ -75,22 +82,15 @@ static int dvb_device_open(struct inode *inode, struct file *file)
if (dvbdev && dvbdev->fops) { if (dvbdev && dvbdev->fops) {
int err = 0; int err = 0;
const struct file_operations *old_fops; const struct file_operations *new_fops;
file->private_data = dvbdev; new_fops = fops_get(dvbdev->fops);
old_fops = file->f_op; if (!new_fops)
file->f_op = fops_get(dvbdev->fops);
if (file->f_op == NULL) {
file->f_op = old_fops;
goto fail; goto fail;
} file->private_data = dvbdev;
replace_fops(file, new_fops);
if (file->f_op->open) if (file->f_op->open)
err = file->f_op->open(inode, file); err = file->f_op->open(inode, file);
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
up_read(&minor_rwsem); up_read(&minor_rwsem);
mutex_unlock(&dvbdev_mutex); mutex_unlock(&dvbdev_mutex);
return err; return err;
@ -188,26 +188,266 @@ skip:
return -ENFILE; return -ENFILE;
} }
static void dvb_media_device_free(struct dvb_device *dvbdev)
{
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
if (dvbdev->entity) {
media_device_unregister_entity(dvbdev->entity);
kfree(dvbdev->entity);
kfree(dvbdev->pads);
dvbdev->entity = NULL;
dvbdev->pads = NULL;
}
if (dvbdev->tsout_entity) {
int i;
for (i = 0; i < dvbdev->tsout_num_entities; i++) {
media_device_unregister_entity(&dvbdev->tsout_entity[i]);
kfree(dvbdev->tsout_entity[i].name);
}
kfree(dvbdev->tsout_entity);
kfree(dvbdev->tsout_pads);
dvbdev->tsout_entity = NULL;
dvbdev->tsout_pads = NULL;
dvbdev->tsout_num_entities = 0;
}
if (dvbdev->intf_devnode) {
media_devnode_remove(dvbdev->intf_devnode);
dvbdev->intf_devnode = NULL;
}
if (dvbdev->adapter->conn) {
media_device_unregister_entity(dvbdev->adapter->conn);
dvbdev->adapter->conn = NULL;
kfree(dvbdev->adapter->conn_pads);
dvbdev->adapter->conn_pads = NULL;
}
#endif
}
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
const char *name, int npads)
{
int i, ret = 0;
dvbdev->tsout_pads = kcalloc(npads, sizeof(*dvbdev->tsout_pads),
GFP_KERNEL);
if (!dvbdev->tsout_pads)
return -ENOMEM;
dvbdev->tsout_entity = kcalloc(npads, sizeof(*dvbdev->tsout_entity),
GFP_KERNEL);
if (!dvbdev->tsout_entity)
return -ENOMEM;
dvbdev->tsout_num_entities = npads;
for (i = 0; i < npads; i++) {
struct media_pad *pads = &dvbdev->tsout_pads[i];
struct media_entity *entity = &dvbdev->tsout_entity[i];
entity->name = kasprintf(GFP_KERNEL, "%s #%d", name, i);
if (!entity->name)
return -ENOMEM;
entity->function = MEDIA_ENT_F_IO_DTV;
pads->flags = MEDIA_PAD_FL_SINK;
ret = media_entity_pads_init(entity, 1, pads);
if (ret < 0)
return ret;
ret = media_device_register_entity(dvbdev->adapter->mdev,
entity);
if (ret < 0)
return ret;
}
return 0;
}
#define DEMUX_TSOUT "demux-tsout"
#define DVR_TSOUT "dvr-tsout"
static int dvb_create_media_entity(struct dvb_device *dvbdev,
int type, int demux_sink_pads)
{
int i, ret, npads;
switch (type) {
case DVB_DEVICE_FRONTEND:
npads = 2;
break;
case DVB_DEVICE_DVR:
ret = dvb_create_tsout_entity(dvbdev, DVR_TSOUT,
demux_sink_pads);
return ret;
case DVB_DEVICE_DEMUX:
npads = 1 + demux_sink_pads;
ret = dvb_create_tsout_entity(dvbdev, DEMUX_TSOUT,
demux_sink_pads);
if (ret < 0)
return ret;
break;
case DVB_DEVICE_CA:
npads = 2;
break;
case DVB_DEVICE_NET:
/*
* We should be creating entities for the MPE/ULE
* decapsulation hardware (or software implementation).
*
* However, the number of for the MPE/ULE decaps may not be
* fixed. As we don't have yet dynamic support for PADs at
* the Media Controller, let's not create the decap
* entities yet.
*/
return 0;
default:
return 0;
}
dvbdev->entity = kzalloc(sizeof(*dvbdev->entity), GFP_KERNEL);
if (!dvbdev->entity)
return -ENOMEM;
dvbdev->entity->name = dvbdev->name;
if (npads) {
dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads),
GFP_KERNEL);
if (!dvbdev->pads)
return -ENOMEM;
}
switch (type) {
case DVB_DEVICE_FRONTEND:
dvbdev->entity->function = MEDIA_ENT_F_DTV_DEMOD;
dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
break;
case DVB_DEVICE_DEMUX:
dvbdev->entity->function = MEDIA_ENT_F_TS_DEMUX;
dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
for (i = 1; i < npads; i++)
dvbdev->pads[i].flags = MEDIA_PAD_FL_SOURCE;
break;
case DVB_DEVICE_CA:
dvbdev->entity->function = MEDIA_ENT_F_DTV_CA;
dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
break;
default:
/* Should never happen, as the first switch prevents it */
kfree(dvbdev->entity);
kfree(dvbdev->pads);
dvbdev->entity = NULL;
dvbdev->pads = NULL;
return 0;
}
if (npads) {
ret = media_entity_pads_init(dvbdev->entity, npads, dvbdev->pads);
if (ret)
return ret;
}
ret = media_device_register_entity(dvbdev->adapter->mdev,
dvbdev->entity);
if (ret)
return ret;
pr_info("%s: media entity '%s' registered.\n",
__func__, dvbdev->entity->name);
return 0;
}
#endif
static int dvb_register_media_device(struct dvb_device *dvbdev,
int type, int minor,
unsigned demux_sink_pads)
{
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
struct media_link *link;
u32 intf_type;
int ret;
if (!dvbdev->adapter->mdev)
return 0;
ret = dvb_create_media_entity(dvbdev, type, demux_sink_pads);
if (ret)
return ret;
switch (type) {
case DVB_DEVICE_FRONTEND:
intf_type = MEDIA_INTF_T_DVB_FE;
break;
case DVB_DEVICE_DEMUX:
intf_type = MEDIA_INTF_T_DVB_DEMUX;
break;
case DVB_DEVICE_DVR:
intf_type = MEDIA_INTF_T_DVB_DVR;
break;
case DVB_DEVICE_CA:
intf_type = MEDIA_INTF_T_DVB_CA;
break;
case DVB_DEVICE_NET:
intf_type = MEDIA_INTF_T_DVB_NET;
break;
default:
return 0;
}
dvbdev->intf_devnode = media_devnode_create(dvbdev->adapter->mdev,
intf_type, 0,
DVB_MAJOR, minor);
if (!dvbdev->intf_devnode)
return -ENOMEM;
/*
* Create the "obvious" link, e. g. the ones that represent
* a direct association between an interface and an entity.
* Other links should be created elsewhere, like:
* DVB FE intf -> tuner
* DVB demux intf -> dvr
*/
if (!dvbdev->entity)
return 0;
link = media_create_intf_link(dvbdev->entity, &dvbdev->intf_devnode->intf,
MEDIA_LNK_FL_ENABLED);
if (!link)
return -ENOMEM;
#endif
return 0;
}
int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
const struct dvb_device *template, void *priv, int type) const struct dvb_device *template, void *priv, int type,
int demux_sink_pads)
{ {
struct dvb_device *dvbdev; struct dvb_device *dvbdev;
struct file_operations *dvbdevfops; struct file_operations *dvbdevfops;
struct device *clsdev; struct device *clsdev;
int minor; int minor;
int id; int id, ret;
mutex_lock(&dvbdev_register_lock); mutex_lock(&dvbdev_register_lock);
if ((id = dvbdev_get_free_id (adap, type)) < 0){ if ((id = dvbdev_get_free_id (adap, type)) < 0){
mutex_unlock(&dvbdev_register_lock); mutex_unlock(&dvbdev_register_lock);
*pdvbdev = NULL; *pdvbdev = NULL;
printk(KERN_ERR "%s: couldn't find free device id\n", __func__); pr_err("%s: couldn't find free device id\n", __func__);
return -ENFILE; return -ENFILE;
} }
*pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); *pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL);
if (!dvbdev){ if (!dvbdev){
mutex_unlock(&dvbdev_register_lock); mutex_unlock(&dvbdev_register_lock);
@ -256,18 +496,30 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
dvb_minors[minor] = dvbdev; dvb_minors[minor] = dvbdev;
up_write(&minor_rwsem); up_write(&minor_rwsem);
ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
if (ret) {
pr_err("%s: dvb_register_media_device failed to create the mediagraph\n",
__func__);
dvb_media_device_free(dvbdev);
kfree(dvbdevfops);
kfree(dvbdev);
up_write(&minor_rwsem);
mutex_unlock(&dvbdev_register_lock);
return ret;
}
mutex_unlock(&dvbdev_register_lock); mutex_unlock(&dvbdev_register_lock);
clsdev = device_create(dvb_class, adap->device, clsdev = device_create(dvb_class, adap->device,
MKDEV(DVB_MAJOR, minor), MKDEV(DVB_MAJOR, minor),
dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id); dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
if (IS_ERR(clsdev)) { if (IS_ERR(clsdev)) {
printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n", pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n",
__func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
return PTR_ERR(clsdev); return PTR_ERR(clsdev);
} }
dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, minor, minor); adap->num, dnames[type], id, minor, minor);
return 0; return 0;
@ -275,7 +527,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
EXPORT_SYMBOL(dvb_register_device); EXPORT_SYMBOL(dvb_register_device);
void dvb_unregister_device(struct dvb_device *dvbdev) void dvb_remove_device(struct dvb_device *dvbdev)
{ {
if (!dvbdev) if (!dvbdev)
return; return;
@ -284,14 +536,244 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
dvb_minors[dvbdev->minor] = NULL; dvb_minors[dvbdev->minor] = NULL;
up_write(&minor_rwsem); up_write(&minor_rwsem);
dvb_media_device_free(dvbdev);
device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
list_del (&dvbdev->list_head); list_del (&dvbdev->list_head);
}
EXPORT_SYMBOL(dvb_remove_device);
void dvb_free_device(struct dvb_device *dvbdev)
{
if (!dvbdev)
return;
kfree (dvbdev->fops); kfree (dvbdev->fops);
kfree (dvbdev); kfree (dvbdev);
} }
EXPORT_SYMBOL(dvb_free_device);
void dvb_unregister_device(struct dvb_device *dvbdev)
{
dvb_remove_device(dvbdev);
dvb_free_device(dvbdev);
}
EXPORT_SYMBOL(dvb_unregister_device); EXPORT_SYMBOL(dvb_unregister_device);
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
static int dvb_create_io_intf_links(struct dvb_adapter *adap,
struct media_interface *intf,
char *name)
{
struct media_device *mdev = adap->mdev;
struct media_entity *entity;
struct media_link *link;
media_device_for_each_entity(entity, mdev) {
if (entity->function == MEDIA_ENT_F_IO_DTV) {
if (strncmp(entity->name, name, strlen(name)))
continue;
link = media_create_intf_link(entity, intf,
MEDIA_LNK_FL_ENABLED);
if (!link)
return -ENOMEM;
}
}
return 0;
}
int dvb_create_media_graph(struct dvb_adapter *adap,
bool create_rf_connector)
{
struct media_device *mdev = adap->mdev;
struct media_entity *entity, *tuner = NULL, *demod = NULL, *conn;
struct media_entity *demux = NULL, *ca = NULL;
struct media_link *link;
struct media_interface *intf;
unsigned demux_pad = 0;
unsigned dvr_pad = 0;
unsigned ntuner = 0, ndemod = 0;
int ret;
static const char *connector_name = "Television";
if (!mdev)
return 0;
media_device_for_each_entity(entity, mdev) {
switch (entity->function) {
case MEDIA_ENT_F_TUNER:
tuner = entity;
ntuner++;
break;
case MEDIA_ENT_F_DTV_DEMOD:
demod = entity;
ndemod++;
break;
case MEDIA_ENT_F_TS_DEMUX:
demux = entity;
break;
case MEDIA_ENT_F_DTV_CA:
ca = entity;
break;
}
}
/*
* Prepare to signalize to media_create_pad_links() that multiple
* entities of the same type exists and a 1:n or n:1 links need to be
* created.
* NOTE: if both tuner and demod have multiple instances, it is up
* to the caller driver to create such links.
*/
if (ntuner > 1)
tuner = NULL;
if (ndemod > 1)
demod = NULL;
if (create_rf_connector) {
conn = kzalloc(sizeof(*conn), GFP_KERNEL);
if (!conn)
return -ENOMEM;
adap->conn = conn;
adap->conn_pads = kzalloc(sizeof(*adap->conn_pads), GFP_KERNEL);
if (!adap->conn_pads)
return -ENOMEM;
conn->flags = MEDIA_ENT_FL_CONNECTOR;
conn->function = MEDIA_ENT_F_CONN_RF;
conn->name = connector_name;
adap->conn_pads->flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(conn, 1, adap->conn_pads);
if (ret)
return ret;
ret = media_device_register_entity(mdev, conn);
if (ret)
return ret;
if (!ntuner)
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_CONN_RF,
conn, 0,
MEDIA_ENT_F_DTV_DEMOD,
demod, 0,
MEDIA_LNK_FL_ENABLED,
false);
else
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_CONN_RF,
conn, 0,
MEDIA_ENT_F_TUNER,
tuner, TUNER_PAD_RF_INPUT,
MEDIA_LNK_FL_ENABLED,
false);
if (ret)
return ret;
}
if (ntuner && ndemod) {
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_TUNER,
tuner, TUNER_PAD_OUTPUT,
MEDIA_ENT_F_DTV_DEMOD,
demod, 0, MEDIA_LNK_FL_ENABLED,
false);
if (ret)
return ret;
}
if (ndemod && demux) {
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_DTV_DEMOD,
demod, 1,
MEDIA_ENT_F_TS_DEMUX,
demux, 0, MEDIA_LNK_FL_ENABLED,
false);
if (ret)
return ret;
}
if (demux && ca) {
ret = media_create_pad_link(demux, 1, ca,
0, MEDIA_LNK_FL_ENABLED);
if (ret)
return ret;
}
/* Create demux links for each ringbuffer/pad */
if (demux) {
media_device_for_each_entity(entity, mdev) {
if (entity->function == MEDIA_ENT_F_IO_DTV) {
if (!strncmp(entity->name, DVR_TSOUT,
strlen(DVR_TSOUT))) {
ret = media_create_pad_link(demux,
++dvr_pad,
entity, 0, 0);
if (ret)
return ret;
}
if (!strncmp(entity->name, DEMUX_TSOUT,
strlen(DEMUX_TSOUT))) {
ret = media_create_pad_link(demux,
++demux_pad,
entity, 0, 0);
if (ret)
return ret;
}
}
}
}
/* Create interface links for FE->tuner, DVR->demux and CA->ca */
media_device_for_each_intf(intf, mdev) {
if (intf->type == MEDIA_INTF_T_DVB_CA && ca) {
link = media_create_intf_link(ca, intf,
MEDIA_LNK_FL_ENABLED);
if (!link)
return -ENOMEM;
}
if (intf->type == MEDIA_INTF_T_DVB_FE && tuner) {
link = media_create_intf_link(tuner, intf,
MEDIA_LNK_FL_ENABLED);
if (!link)
return -ENOMEM;
}
#if 0
/*
* Indirect link - let's not create yet, as we don't know how
* to handle indirect links, nor if this will
* actually be needed.
*/
if (intf->type == MEDIA_INTF_T_DVB_DVR && demux) {
link = media_create_intf_link(demux, intf,
MEDIA_LNK_FL_ENABLED);
if (!link)
return -ENOMEM;
}
#endif
if (intf->type == MEDIA_INTF_T_DVB_DVR) {
ret = dvb_create_io_intf_links(adap, intf, DVR_TSOUT);
if (ret)
return ret;
}
if (intf->type == MEDIA_INTF_T_DVB_DEMUX) {
ret = dvb_create_io_intf_links(adap, intf, DEMUX_TSOUT);
if (ret)
return ret;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(dvb_create_media_graph);
#endif
static int dvbdev_check_free_adapter_num(int num) static int dvbdev_check_free_adapter_num(int num)
{ {
struct list_head *entry; struct list_head *entry;
@ -347,7 +829,7 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
memset (adap, 0, sizeof(struct dvb_adapter)); memset (adap, 0, sizeof(struct dvb_adapter));
INIT_LIST_HEAD (&adap->device_list); INIT_LIST_HEAD (&adap->device_list);
printk(KERN_INFO "DVB: registering new adapter (%s)\n", name); pr_info("DVB: registering new adapter (%s)\n", name);
adap->num = num; adap->num = num;
adap->name = name; adap->name = name;
@ -419,11 +901,8 @@ int dvb_usercopy(struct file *file,
} }
/* call driver */ /* call driver */
/* this lock is much too coarse */
//mutex_lock(&dvbdev_mutex);
if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD) if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
err = -ENOTTY; err = -ENOTTY;
//mutex_unlock(&dvbdev_mutex);
if (err < 0) if (err < 0)
goto out; goto out;
@ -454,11 +933,7 @@ static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0; return 0;
} }
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0))
static char *dvb_devnode(struct device *dev, mode_t *mode)
#else
static char *dvb_devnode(struct device *dev, umode_t *mode) static char *dvb_devnode(struct device *dev, umode_t *mode)
#endif
{ {
struct dvb_device *dvbdev = dev_get_drvdata(dev); struct dvb_device *dvbdev = dev_get_drvdata(dev);
@ -473,13 +948,13 @@ static int __init init_dvbdev(void)
dev_t dev = MKDEV(DVB_MAJOR, 0); dev_t dev = MKDEV(DVB_MAJOR, 0);
if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) { if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR); pr_err("dvb-core: unable to get major %d\n", DVB_MAJOR);
return retval; return retval;
} }
cdev_init(&dvb_device_cdev, &dvb_device_fops); cdev_init(&dvb_device_cdev, &dvb_device_fops);
if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) { if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
printk(KERN_ERR "dvb-core: unable register character device\n"); pr_err("dvb-core: unable register character device\n");
goto error; goto error;
} }

View File

@ -14,10 +14,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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 _DVBDEV_H_ #ifndef _DVBDEV_H_
@ -27,6 +23,7 @@
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/list.h> #include <linux/list.h>
#include <media/media-device.h>
#define DVB_MAJOR 212 #define DVB_MAJOR 212
@ -60,6 +57,28 @@
struct dvb_frontend; struct dvb_frontend;
/**
* struct dvb_adapter - represents a Digital TV adapter using Linux DVB API
*
* @num: Number of the adapter
* @list_head: List with the DVB adapters
* @device_list: List with the DVB devices
* @name: Name of the adapter
* @proposed_mac: proposed MAC address for the adapter
* @priv: private data
* @device: pointer to struct device
* @module: pointer to struct module
* @mfe_shared: mfe shared: indicates mutually exclusive frontends
* Thie usage of this flag is currently deprecated
* @mfe_dvbdev: Frontend device in use, in the case of MFE
* @mfe_lock: Lock to prevent using the other frontends when MFE is
* used.
* @mdev: pointer to struct media_device, used when the media
* controller is used.
* @conn: RF connector. Used only if the device has no separate
* tuner.
* @conn_pads: pointer to struct media_pad associated with @conn;
*/
struct dvb_adapter { struct dvb_adapter {
int num; int num;
struct list_head list_head; struct list_head list_head;
@ -75,9 +94,47 @@ struct dvb_adapter {
int mfe_shared; /* indicates mutually exclusive frontends */ int mfe_shared; /* indicates mutually exclusive frontends */
struct dvb_device *mfe_dvbdev; /* frontend device in use */ struct dvb_device *mfe_dvbdev; /* frontend device in use */
struct mutex mfe_lock; /* access lock for thread creation */ struct mutex mfe_lock; /* access lock for thread creation */
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
struct media_device *mdev;
struct media_entity *conn;
struct media_pad *conn_pads;
#endif
}; };
/**
* struct dvb_device - represents a DVB device node
*
* @list_head: List head with all DVB devices
* @fops: pointer to struct file_operations
* @adapter: pointer to the adapter that holds this device node
* @type: type of the device: DVB_DEVICE_SEC, DVB_DEVICE_FRONTEND,
* DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_CA, DVB_DEVICE_NET
* @minor: devnode minor number. Major number is always DVB_MAJOR.
* @id: device ID number, inside the adapter
* @readers: Initialized by the caller. Each call to open() in Read Only mode
* decreases this counter by one.
* @writers: Initialized by the caller. Each call to open() in Read/Write
* mode decreases this counter by one.
* @users: Initialized by the caller. Each call to open() in any mode
* decreases this counter by one.
* @wait_queue: wait queue, used to wait for certain events inside one of
* the DVB API callers
* @kernel_ioctl: callback function used to handle ioctl calls from userspace.
* @name: Name to be used for the device at the Media Controller
* @entity: pointer to struct media_entity associated with the device node
* @pads: pointer to struct media_pad associated with @entity;
* @priv: private data
* @intf_devnode: Pointer to media_intf_devnode. Used by the dvbdev core to
* store the MC device node interface
* @tsout_num_entities: Number of Transport Stream output entities
* @tsout_entity: array with MC entities associated to each TS output node
* @tsout_pads: array with the source pads for each @tsout_entity
*
* This structure is used by the DVB core (frontend, CA, net, demux) in
* order to create the device nodes. Usually, driver should not initialize
* this struct diretly.
*/
struct dvb_device { struct dvb_device {
struct list_head list_head; struct list_head list_head;
const struct file_operations *fops; const struct file_operations *fops;
@ -96,33 +153,144 @@ struct dvb_device {
/* don't really need those !? -- FIXME: use video_usercopy */ /* don't really need those !? -- FIXME: use video_usercopy */
int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg); int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg);
/* Needed for media controller register/unregister */
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
const char *name;
/* Allocated and filled inside dvbdev.c */
struct media_intf_devnode *intf_devnode;
unsigned tsout_num_entities;
struct media_entity *entity, *tsout_entity;
struct media_pad *pads, *tsout_pads;
#endif
void *priv; void *priv;
}; };
/**
extern int dvb_register_adapter(struct dvb_adapter *adap, const char *name, * dvb_register_adapter - Registers a new DVB adapter
*
* @adap: pointer to struct dvb_adapter
* @name: Adapter's name
* @module: initialized with THIS_MODULE at the caller
* @device: pointer to struct device that corresponds to the device driver
* @adapter_nums: Array with a list of the numbers for @dvb_register_adapter;
* to select among them. Typically, initialized with:
* DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nums)
*/
int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
struct module *module, struct device *device, struct module *module, struct device *device,
short *adapter_nums); short *adapter_nums);
extern int dvb_unregister_adapter (struct dvb_adapter *adap);
extern int dvb_register_device (struct dvb_adapter *adap, /**
* dvb_unregister_adapter - Unregisters a DVB adapter
*
* @adap: pointer to struct dvb_adapter
*/
int dvb_unregister_adapter(struct dvb_adapter *adap);
/**
* dvb_register_device - Registers a new DVB device
*
* @adap: pointer to struct dvb_adapter
* @pdvbdev: pointer to the place where the new struct dvb_device will be
* stored
* @template: Template used to create &pdvbdev;
* @priv: private data
* @type: type of the device: %DVB_DEVICE_SEC, %DVB_DEVICE_FRONTEND,
* %DVB_DEVICE_DEMUX, %DVB_DEVICE_DVR, %DVB_DEVICE_CA,
* %DVB_DEVICE_NET
* @demux_sink_pads: Number of demux outputs, to be used to create the TS
* outputs via the Media Controller.
*/
int dvb_register_device(struct dvb_adapter *adap,
struct dvb_device **pdvbdev, struct dvb_device **pdvbdev,
const struct dvb_device *template, const struct dvb_device *template,
void *priv, void *priv,
int type); int type,
int demux_sink_pads);
extern void dvb_unregister_device (struct dvb_device *dvbdev); /**
* dvb_remove_device - Remove a registered DVB device
*
* This does not free memory. To do that, call dvb_free_device().
*
* @dvbdev: pointer to struct dvb_device
*/
void dvb_remove_device(struct dvb_device *dvbdev);
extern int dvb_generic_open (struct inode *inode, struct file *file); /**
extern int dvb_generic_release (struct inode *inode, struct file *file); * dvb_free_device - Free memory occupied by a DVB device.
extern long dvb_generic_ioctl (struct file *file, *
* Call dvb_unregister_device() before calling this function.
*
* @dvbdev: pointer to struct dvb_device
*/
void dvb_free_device(struct dvb_device *dvbdev);
/**
* dvb_unregister_device - Unregisters a DVB device
*
* This is a combination of dvb_remove_device() and dvb_free_device().
* Using this function is usually a mistake, and is often an indicator
* for a use-after-free bug (when a userspace process keeps a file
* handle to a detached device).
*
* @dvbdev: pointer to struct dvb_device
*/
void dvb_unregister_device(struct dvb_device *dvbdev);
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
/**
* dvb_create_media_graph - Creates media graph for the Digital TV part of the
* device.
*
* @adap: pointer to struct dvb_adapter
* @create_rf_connector: if true, it creates the RF connector too
*
* This function checks all DVB-related functions at the media controller
* entities and creates the needed links for the media graph. It is
* capable of working with multiple tuners or multiple frontends, but it
* won't create links if the device has multiple tuners and multiple frontends
* or if the device has multiple muxes. In such case, the caller driver should
* manually create the remaining links.
*/
__must_check int dvb_create_media_graph(struct dvb_adapter *adap,
bool create_rf_connector);
static inline void dvb_register_media_controller(struct dvb_adapter *adap,
struct media_device *mdev)
{
adap->mdev = mdev;
}
static inline struct media_device
*dvb_get_media_controller(struct dvb_adapter *adap)
{
return adap->mdev;
}
#else
static inline
int dvb_create_media_graph(struct dvb_adapter *adap,
bool create_rf_connector)
{
return 0;
};
#define dvb_register_media_controller(a, b) {}
#define dvb_get_media_controller(a) NULL
#endif
int dvb_generic_open (struct inode *inode, struct file *file);
int dvb_generic_release (struct inode *inode, struct file *file);
long dvb_generic_ioctl (struct file *file,
unsigned int cmd, unsigned long arg); unsigned int cmd, unsigned long arg);
/* we don't mess with video_usercopy() any more, /* we don't mess with video_usercopy() any more,
we simply define out own dvb_usercopy(), which will hopefully become we simply define out own dvb_usercopy(), which will hopefully become
generic_usercopy() someday... */ generic_usercopy() someday... */
extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
int (*func)(struct file *file, unsigned int cmd, void *arg)); int (*func)(struct file *file, unsigned int cmd, void *arg));
/** generic DVB attach function. */ /** generic DVB attach function. */
@ -140,11 +308,15 @@ extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
__r; \ __r; \
}) })
#define dvb_detach(FUNC) symbol_put_addr(FUNC)
#else #else
#define dvb_attach(FUNCTION, ARGS...) ({ \ #define dvb_attach(FUNCTION, ARGS...) ({ \
FUNCTION(ARGS); \ FUNCTION(ARGS); \
}) })
#define dvb_detach(FUNC) {}
#endif #endif
#endif /* #ifndef _DVBDEV_H_ */ #endif /* #ifndef _DVBDEV_H_ */

View File

@ -1679,7 +1679,7 @@ static int get_stats(struct dvb_frontend *fe)
} }
static int read_status(struct dvb_frontend *fe, fe_status_t *status) static int read_status(struct dvb_frontend *fe, enum fe_status *status)
{ {
struct cxd_state *state = fe->demodulator_priv; struct cxd_state *state = fe->demodulator_priv;
u8 rdata; u8 rdata;
@ -2191,7 +2191,7 @@ static int read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
static int tune(struct dvb_frontend *fe, bool re_tune, static int tune(struct dvb_frontend *fe, bool re_tune,
unsigned int mode_flags, unsigned int mode_flags,
unsigned int *delay, fe_status_t *status) unsigned int *delay, enum fe_status *status)
{ {
struct cxd_state *state = fe->demodulator_priv; struct cxd_state *state = fe->demodulator_priv;
int r; int r;
@ -2217,7 +2217,7 @@ static enum dvbfe_search search(struct dvb_frontend *fe)
{ {
int r; int r;
u32 loops = 20, i; u32 loops = 20, i;
fe_status_t status; enum fe_status status;
r = set_parameters(fe); r = set_parameters(fe);
@ -2241,10 +2241,9 @@ static int get_algo(struct dvb_frontend *fe)
return DVBFE_ALGO_HW; return DVBFE_ALGO_HW;
} }
static int get_fe_t2(struct cxd_state *state) static int get_fe_t2(struct cxd_state *state, struct dtv_frontend_properties *p)
{ {
struct dvb_frontend *fe = &state->frontend; struct dvb_frontend *fe = &state->frontend;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u8 ofdm[5], modcod[2]; u8 ofdm[5], modcod[2];
freeze_regst(state); freeze_regst(state);
@ -2345,10 +2344,9 @@ static int get_fe_t2(struct cxd_state *state)
return 0; return 0;
} }
static int get_fe_t(struct cxd_state *state) static int get_fe_t(struct cxd_state *state, struct dtv_frontend_properties *p)
{ {
struct dvb_frontend *fe = &state->frontend; struct dvb_frontend *fe = &state->frontend;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u8 tps[7]; u8 tps[7];
read_tps(state, tps); read_tps(state, tps);
@ -2447,10 +2445,9 @@ static int get_fe_t(struct cxd_state *state)
return 0; return 0;
} }
static int get_fe_c(struct cxd_state *state) static int get_fe_c(struct cxd_state *state, struct dtv_frontend_properties *p)
{ {
struct dvb_frontend *fe = &state->frontend; struct dvb_frontend *fe = &state->frontend;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u8 qam; u8 qam;
freeze_regst(state); freeze_regst(state);
@ -2460,7 +2457,7 @@ static int get_fe_c(struct cxd_state *state)
return 0; return 0;
} }
static int get_frontend(struct dvb_frontend *fe) static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{ {
struct cxd_state *state = fe->demodulator_priv; struct cxd_state *state = fe->demodulator_priv;
@ -2469,13 +2466,13 @@ static int get_frontend(struct dvb_frontend *fe)
switch (state->state) { switch (state->state) {
case ActiveT: case ActiveT:
get_fe_t(state); get_fe_t(state, p);
break; break;
case ActiveT2: case ActiveT2:
get_fe_t2(state); get_fe_t2(state, p);
break; break;
case ActiveC: case ActiveC:
get_fe_c(state); get_fe_c(state, p);
break; break;
case ActiveC2: case ActiveC2:
break; break;

View File

@ -4892,14 +4892,14 @@ static int drxk_set_parameters (struct dvb_frontend *fe,
return 0; return 0;
} }
static int drxk_c_get_frontend(struct dvb_frontend *fe) static int drxk_c_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{ {
//struct drxk_state *state = fe->demodulator_priv; //struct drxk_state *state = fe->demodulator_priv;
//printk("%s\n", __FUNCTION__); //printk("%s\n", __FUNCTION__);
return 0; return 0;
} }
static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status) static int drxk_read_status(struct dvb_frontend *fe, enum fe_status *status)
{ {
struct drxk_state *state = fe->demodulator_priv; struct drxk_state *state = fe->demodulator_priv;
u32 stat; u32 stat;
@ -4986,7 +4986,7 @@ static int drxk_t_sleep(struct dvb_frontend* fe)
return 0; return 0;
} }
static int drxk_t_get_frontend(struct dvb_frontend *fe) static int drxk_t_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{ {
//struct drxk_state *state = fe->demodulator_priv; //struct drxk_state *state = fe->demodulator_priv;
//printk("%s\n", __FUNCTION__); //printk("%s\n", __FUNCTION__);

View File

@ -62,7 +62,7 @@ static int lnbh25_write_regs(struct lnbh25 *lnbh, int reg, int len)
} }
static int lnbh25_set_voltage(struct dvb_frontend *fe, static int lnbh25_set_voltage(struct dvb_frontend *fe,
fe_sec_voltage_t voltage) enum fe_sec_voltage voltage)
{ {
struct lnbh25 *lnbh = (struct lnbh25 *) fe->sec_priv; struct lnbh25 *lnbh = (struct lnbh25 *) fe->sec_priv;
u8 oldreg0 = lnbh->reg[0]; u8 oldreg0 = lnbh->reg[0];
@ -107,7 +107,7 @@ static int lnbh25_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
} }
static int lnbh25_set_tone(struct dvb_frontend *fe, static int lnbh25_set_tone(struct dvb_frontend *fe,
fe_sec_tone_mode_t tone) enum fe_sec_tone_mode tone)
{ {
/* struct lnbh25 *lnbh = (struct lnbh25 *) fe->sec_priv; */ /* struct lnbh25 *lnbh = (struct lnbh25 *) fe->sec_priv; */

View File

@ -45,7 +45,7 @@ struct lnbp21 {
}; };
static int lnbp21_set_voltage(struct dvb_frontend *fe, static int lnbp21_set_voltage(struct dvb_frontend *fe,
fe_sec_voltage_t voltage) enum fe_sec_voltage voltage)
{ {
struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv; struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0, struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0,
@ -98,7 +98,7 @@ static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
} }
static int lnbp21_set_tone(struct dvb_frontend *fe, static int lnbp21_set_tone(struct dvb_frontend *fe,
fe_sec_tone_mode_t tone) enum fe_sec_tone_mode tone)
{ {
struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv; struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0, struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0,

View File

@ -560,7 +560,7 @@ static int set_parameters(struct dvb_frontend *fe)
static int get_stats(struct dvb_frontend *fe); static int get_stats(struct dvb_frontend *fe);
static int read_status(struct dvb_frontend *fe, fe_status_t *status) static int read_status(struct dvb_frontend *fe, enum fe_status *status)
{ {
struct mxl *state = fe->demodulator_priv; struct mxl *state = fe->demodulator_priv;
@ -582,10 +582,10 @@ static int read_status(struct dvb_frontend *fe, fe_status_t *status)
static int tune(struct dvb_frontend *fe, bool re_tune, static int tune(struct dvb_frontend *fe, bool re_tune,
unsigned int mode_flags, unsigned int mode_flags,
unsigned int *delay, fe_status_t *status) unsigned int *delay, enum fe_status *status)
{ {
struct mxl *state = fe->demodulator_priv; struct mxl *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache; /* struct dtv_frontend_properties *p = &fe->dtv_property_cache; */
int r = 0; int r = 0;
*delay = HZ / 2; *delay = HZ / 2;
@ -659,7 +659,7 @@ static int read_ber(struct dvb_frontend *fe, u32 *ber)
{ {
struct mxl *state = fe->demodulator_priv; struct mxl *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 reg[8], reg2[4], n = 0, d = 0; u32 reg[8], reg2[4];
int stat; int stat;
*ber = 0; *ber = 0;
@ -748,7 +748,7 @@ static int get_stats(struct dvb_frontend *fe)
return 0; return 0;
} }
static fe_code_rate_t conv_fec(MXL_HYDRA_FEC_E fec) static enum fe_code_rate conv_fec(MXL_HYDRA_FEC_E fec)
{ {
enum fe_code_rate fec2fec[11] = { enum fe_code_rate fec2fec[11] = {
FEC_NONE, FEC_1_2, FEC_3_5, FEC_2_3, FEC_NONE, FEC_1_2, FEC_3_5, FEC_2_3,
@ -761,10 +761,9 @@ static fe_code_rate_t conv_fec(MXL_HYDRA_FEC_E fec)
return fec2fec[fec]; return fec2fec[fec];
} }
static int get_frontend(struct dvb_frontend *fe) static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{ {
struct mxl *state = fe->demodulator_priv; struct mxl *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 regData[MXL_DEMOD_CHAN_PARAMS_BUFF_SIZE]; u32 regData[MXL_DEMOD_CHAN_PARAMS_BUFF_SIZE];
u32 freq; u32 freq;
int stat; int stat;

View File

@ -58,7 +58,7 @@ enum EDemodState { Off, QAMSet, OFDMSet, QAMStarted, OFDMStarted };
struct stv_state { struct stv_state {
struct dvb_frontend frontend; struct dvb_frontend frontend;
fe_modulation_t modulation; enum fe_modulation modulation;
u32 symbol_rate; u32 symbol_rate;
u32 bandwidth; u32 bandwidth;
struct device *dev; struct device *dev;
@ -1861,7 +1861,7 @@ static int OFDM_GetLockStatus(struct stv_state *state, LOCK_STATUS* pLockStatus,
#endif #endif
static int read_status(struct dvb_frontend *fe, fe_status_t *status) static int read_status(struct dvb_frontend *fe, enum fe_status *status)
{ {
struct stv_state *state = fe->demodulator_priv; struct stv_state *state = fe->demodulator_priv;
*status=0; *status=0;

View File

@ -5072,10 +5072,9 @@ static int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir,
return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg); return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg);
} }
static int stv090x_get_frontend(struct dvb_frontend *fe) static int stv090x_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{ {
struct stv090x_state *state = fe->demodulator_priv; struct stv090x_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u8 tmp; u8 tmp;
u32 reg = 0; u32 reg = 0;

View File

@ -849,10 +849,12 @@ static int init_search_param(struct stv *state)
read_reg(state, RSTV0910_P2_PDELCTRL1 + state->regoff, &tmp); read_reg(state, RSTV0910_P2_PDELCTRL1 + state->regoff, &tmp);
tmp |= 0x20; // Filter_en (no effect if SIS=non-MIS tmp |= 0x20; // Filter_en (no effect if SIS=non-MIS
tmp &= ~0x20; // Filter_en (no effect if SIS=non-MIS
write_reg(state, RSTV0910_P2_PDELCTRL1 + state->regoff, tmp); write_reg(state, RSTV0910_P2_PDELCTRL1 + state->regoff, tmp);
read_reg(state, RSTV0910_P2_PDELCTRL2 + state->regoff, &tmp); read_reg(state, RSTV0910_P2_PDELCTRL2 + state->regoff, &tmp);
tmp &= ~0x02; // frame mode = 0 tmp &= ~0x02; // frame mode = 0
tmp |= 0x80; // frame mode = 0
write_reg(state, RSTV0910_P2_PDELCTRL2 + state->regoff, tmp); write_reg(state, RSTV0910_P2_PDELCTRL2 + state->regoff, tmp);
write_reg(state, RSTV0910_P2_UPLCCST0 + state->regoff, 0xe0); write_reg(state, RSTV0910_P2_UPLCCST0 + state->regoff, 0xe0);
@ -1260,10 +1262,9 @@ static int get_frequency_offset(struct stv *state, s32 *off)
return 0; return 0;
} }
static int get_frontend(struct dvb_frontend *fe) static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{ {
struct stv *state = fe->demodulator_priv; struct stv *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u8 tmp; u8 tmp;
if (state->receive_mode == RCVMODE_DVBS2) { if (state->receive_mode == RCVMODE_DVBS2) {
@ -1345,7 +1346,7 @@ static int read_snr(struct dvb_frontend *fe, u16 *snr);
static int read_signal_strength(struct dvb_frontend *fe, u16 *strength); static int read_signal_strength(struct dvb_frontend *fe, u16 *strength);
static int read_ber(struct dvb_frontend *fe, u32 *ber); static int read_ber(struct dvb_frontend *fe, u32 *ber);
static int read_status(struct dvb_frontend *fe, fe_status_t *status) static int read_status(struct dvb_frontend *fe, enum fe_status *status)
{ {
struct stv *state = fe->demodulator_priv; struct stv *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct dtv_frontend_properties *p = &fe->dtv_property_cache;
@ -1528,7 +1529,7 @@ get_stat:
static int tune(struct dvb_frontend *fe, bool re_tune, static int tune(struct dvb_frontend *fe, bool re_tune,
unsigned int mode_flags, unsigned int mode_flags,
unsigned int *delay, fe_status_t *status) unsigned int *delay, enum fe_status *status)
{ {
struct stv *state = fe->demodulator_priv; struct stv *state = fe->demodulator_priv;
int r; int r;
@ -1554,7 +1555,7 @@ static int get_algo(struct dvb_frontend *fe)
return DVBFE_ALGO_HW; return DVBFE_ALGO_HW;
} }
static int set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) static int set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone)
{ {
struct stv *state = fe->demodulator_priv; struct stv *state = fe->demodulator_priv;
u16 offs = state->nr ? 0x40 : 0; u16 offs = state->nr ? 0x40 : 0;
@ -1608,7 +1609,7 @@ static int recv_slave_reply(struct dvb_frontend *fe,
return 0; return 0;
} }
static int send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) static int send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd burst)
{ {
#if 0 #if 0
struct stv *state = fe->demodulator_priv; struct stv *state = fe->demodulator_priv;

View File

@ -32,6 +32,9 @@
#include "stv6110x.h" #include "stv6110x.h"
#include "stv6110x_priv.h" #include "stv6110x_priv.h"
/* Max transfer size done by I2C transfer functions */
#define MAX_XFER_SIZE 64
static unsigned int verbose; static unsigned int verbose;
module_param(verbose, int, 0644); module_param(verbose, int, 0644);
MODULE_PARM_DESC(verbose, "Set Verbosity level"); MODULE_PARM_DESC(verbose, "Set Verbosity level");
@ -61,7 +64,8 @@ static int stv6110x_write_regs(struct stv6110x_state *stv6110x, int start, u8 da
{ {
int ret; int ret;
const struct stv6110x_config *config = stv6110x->config; const struct stv6110x_config *config = stv6110x->config;
u8 buf[len + 1]; u8 buf[MAX_XFER_SIZE];
struct i2c_msg msg = { struct i2c_msg msg = {
.addr = config->addr, .addr = config->addr,
.flags = 0, .flags = 0,
@ -69,6 +73,13 @@ static int stv6110x_write_regs(struct stv6110x_state *stv6110x, int start, u8 da
.len = len + 1 .len = len + 1
}; };
if (1 + len > sizeof(buf)) {
printk(KERN_WARNING
"%s: i2c wr: len=%d is too big!\n",
KBUILD_MODNAME, len);
return -EINVAL;
}
if (start + len > 8) if (start + len > 8)
return -EINVAL; return -EINVAL;
@ -324,17 +335,15 @@ static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status)
} }
static int stv6110x_release(struct dvb_frontend *fe) static void stv6110x_release(struct dvb_frontend *fe)
{ {
struct stv6110x_state *stv6110x = fe->tuner_priv; struct stv6110x_state *stv6110x = fe->tuner_priv;
fe->tuner_priv = NULL; fe->tuner_priv = NULL;
kfree(stv6110x); kfree(stv6110x);
return 0;
} }
static struct dvb_tuner_ops stv6110x_ops = { static const struct dvb_tuner_ops stv6110x_ops = {
.info = { .info = {
.name = "STV6110(A) Silicon Tuner", .name = "STV6110(A) Silicon Tuner",
.frequency_min = 950000, .frequency_min = 950000,
@ -344,7 +353,7 @@ static struct dvb_tuner_ops stv6110x_ops = {
.release = stv6110x_release .release = stv6110x_release
}; };
static struct stv6110x_devctl stv6110x_ctl = { static const struct stv6110x_devctl stv6110x_ctl = {
.tuner_init = stv6110x_init, .tuner_init = stv6110x_init,
.tuner_sleep = stv6110x_sleep, .tuner_sleep = stv6110x_sleep,
.tuner_set_mode = stv6110x_set_mode, .tuner_set_mode = stv6110x_set_mode,
@ -358,7 +367,7 @@ static struct stv6110x_devctl stv6110x_ctl = {
.tuner_get_status = stv6110x_get_status, .tuner_get_status = stv6110x_get_status,
}; };
struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_config *config, const struct stv6110x_config *config,
struct i2c_adapter *i2c) struct i2c_adapter *i2c)
{ {

View File

@ -53,14 +53,20 @@ struct stv6110x_devctl {
}; };
#if defined(CONFIG_DVB_STV6110x) || (defined(CONFIG_DVB_STV6110x_MODULE) && defined(MODULE)) #include <linux/version.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0))
#define IS_REACHABLE(option) (config_enabled(option) || \
(config_enabled(option##_MODULE) && config_enabled(MODULE)))
#endif
extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, #if IS_REACHABLE(CONFIG_DVB_STV6110x)
extern const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_config *config, const struct stv6110x_config *config,
struct i2c_adapter *i2c); struct i2c_adapter *i2c);
#else #else
static inline struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, static inline const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_config *config, const struct stv6110x_config *config,
struct i2c_adapter *i2c) struct i2c_adapter *i2c)
{ {

View File

@ -70,7 +70,7 @@ struct stv6110x_state {
const struct stv6110x_config *config; const struct stv6110x_config *config;
u8 regs[8]; u8 regs[8];
struct stv6110x_devctl *devctl; const struct stv6110x_devctl *devctl;
}; };
#endif /* __STV6110x_PRIV_H */ #endif /* __STV6110x_PRIV_H */

View File

@ -203,11 +203,10 @@ static int init(struct dvb_frontend *fe)
return 0; return 0;
} }
static int release(struct dvb_frontend *fe) static void release(struct dvb_frontend *fe)
{ {
kfree(fe->tuner_priv); kfree(fe->tuner_priv);
fe->tuner_priv = NULL; fe->tuner_priv = NULL;
return 0;
} }
static int set_bandwidth(struct dvb_frontend *fe, u32 CutOffFrequency) static int set_bandwidth(struct dvb_frontend *fe, u32 CutOffFrequency)

View File

@ -790,11 +790,10 @@ static int init(struct dvb_frontend *fe)
return 0; return 0;
} }
static int release(struct dvb_frontend *fe) static void release(struct dvb_frontend *fe)
{ {
kfree(fe->tuner_priv); kfree(fe->tuner_priv);
fe->tuner_priv = NULL; fe->tuner_priv = NULL;
return 0;
} }
static int set_params(struct dvb_frontend *fe) static int set_params(struct dvb_frontend *fe)

View File

@ -1144,11 +1144,10 @@ static int init(struct dvb_frontend *fe)
return 0; return 0;
} }
static int release(struct dvb_frontend *fe) static void release(struct dvb_frontend *fe)
{ {
kfree(fe->tuner_priv); kfree(fe->tuner_priv);
fe->tuner_priv = NULL; fe->tuner_priv = NULL;
return 0;
} }
/* /*

View File

@ -24,67 +24,131 @@
#ifndef _DVBCA_H_ #ifndef _DVBCA_H_
#define _DVBCA_H_ #define _DVBCA_H_
/* slot interface types and info */ /**
* struct ca_slot_info - CA slot interface types and info.
*
* @num: slot number.
* @type: slot type.
* @flags: flags applicable to the slot.
*
* This struct stores the CA slot information.
*
* @type can be:
*
* - %CA_CI - CI high level interface;
* - %CA_CI_LINK - CI link layer level interface;
* - %CA_CI_PHYS - CI physical layer level interface;
* - %CA_DESCR - built-in descrambler;
* - %CA_SC -simple smart card interface.
*
* @flags can be:
*
* - %CA_CI_MODULE_PRESENT - module (or card) inserted;
* - %CA_CI_MODULE_READY - module is ready for usage.
*/
typedef struct ca_slot_info { struct ca_slot_info {
int num; /* slot number */ int num;
int type;
int type; /* CA interface this slot supports */ #define CA_CI 1
#define CA_CI 1 /* CI high level interface */ #define CA_CI_LINK 2
#define CA_CI_LINK 2 /* CI link layer level interface */ #define CA_CI_PHYS 4
#define CA_CI_PHYS 4 /* CI physical layer level interface */ #define CA_DESCR 8
#define CA_DESCR 8 /* built-in descrambler */ #define CA_SC 128
#define CA_SC 128 /* simple smart card interface */
unsigned int flags; unsigned int flags;
#define CA_CI_MODULE_PRESENT 1 /* module (or card) inserted */ #define CA_CI_MODULE_PRESENT 1
#define CA_CI_MODULE_READY 2 #define CA_CI_MODULE_READY 2
} ca_slot_info_t; };
/* descrambler types and info */ /**
* struct ca_descr_info - descrambler types and info.
typedef struct ca_descr_info { *
unsigned int num; /* number of available descramblers (keys) */ * @num: number of available descramblers (keys).
unsigned int type; /* type of supported scrambling system */ * @type: type of supported scrambling system.
*
* Identifies the number of descramblers and their type.
*
* @type can be:
*
* - %CA_ECD - European Common Descrambler (ECD) hardware;
* - %CA_NDS - Videoguard (NDS) hardware;
* - %CA_DSS - Distributed Sample Scrambling (DSS) hardware.
*/
struct ca_descr_info {
unsigned int num;
unsigned int type;
#define CA_ECD 1 #define CA_ECD 1
#define CA_NDS 2 #define CA_NDS 2
#define CA_DSS 4 #define CA_DSS 4
} ca_descr_info_t; };
typedef struct ca_caps { /**
unsigned int slot_num; /* total number of CA card and module slots */ * struct ca_caps - CA slot interface capabilities.
unsigned int slot_type; /* OR of all supported types */ *
unsigned int descr_num; /* total number of descrambler slots (keys) */ * @slot_num: total number of CA card and module slots.
unsigned int descr_type; /* OR of all supported types */ * @slot_type: bitmap with all supported types as defined at
} ca_caps_t; * &struct ca_slot_info (e. g. %CA_CI, %CA_CI_LINK, etc).
* @descr_num: total number of descrambler slots (keys)
* @descr_type: bitmap with all supported types as defined at
* &struct ca_descr_info (e. g. %CA_ECD, %CA_NDS, etc).
*/
struct ca_caps {
unsigned int slot_num;
unsigned int slot_type;
unsigned int descr_num;
unsigned int descr_type;
};
/* a message to/from a CI-CAM */ /**
typedef struct ca_msg { * struct ca_msg - a message to/from a CI-CAM
*
* @index: unused
* @type: unused
* @length: length of the message
* @msg: message
*
* This struct carries a message to be send/received from a CI CA module.
*/
struct ca_msg {
unsigned int index; unsigned int index;
unsigned int type; unsigned int type;
unsigned int length; unsigned int length;
unsigned char msg[256]; unsigned char msg[256];
} ca_msg_t; };
typedef struct ca_descr { /**
* struct ca_descr - CA descrambler control words info
*
* @index: CA Descrambler slot
* @parity: control words parity, where 0 means even and 1 means odd
* @cw: CA Descrambler control words
*/
struct ca_descr {
unsigned int index; unsigned int index;
unsigned int parity; /* 0 == even, 1 == odd */ unsigned int parity;
unsigned char cw[8]; unsigned char cw[8];
} ca_descr_t; };
typedef struct ca_pid {
unsigned int pid;
int index; /* -1 == disable*/
} ca_pid_t;
#define CA_RESET _IO('o', 128) #define CA_RESET _IO('o', 128)
#define CA_GET_CAP _IOR('o', 129, ca_caps_t) #define CA_GET_CAP _IOR('o', 129, struct ca_caps)
#define CA_GET_SLOT_INFO _IOR('o', 130, ca_slot_info_t) #define CA_GET_SLOT_INFO _IOR('o', 130, struct ca_slot_info)
#define CA_GET_DESCR_INFO _IOR('o', 131, ca_descr_info_t) #define CA_GET_DESCR_INFO _IOR('o', 131, struct ca_descr_info)
#define CA_GET_MSG _IOR('o', 132, ca_msg_t) #define CA_GET_MSG _IOR('o', 132, struct ca_msg)
#define CA_SEND_MSG _IOW('o', 133, ca_msg_t) #define CA_SEND_MSG _IOW('o', 133, struct ca_msg)
#define CA_SET_DESCR _IOW('o', 134, ca_descr_t) #define CA_SET_DESCR _IOW('o', 134, struct ca_descr)
#define CA_SET_PID _IOW('o', 135, ca_pid_t)
#if !defined(__KERNEL__)
/* This is needed for legacy userspace support */
typedef struct ca_slot_info ca_slot_info_t;
typedef struct ca_descr_info ca_descr_info_t;
typedef struct ca_caps ca_caps_t;
typedef struct ca_msg ca_msg_t;
typedef struct ca_descr ca_descr_t;
#endif
#endif #endif

View File

@ -32,27 +32,74 @@
#define DMX_FILTER_SIZE 16 #define DMX_FILTER_SIZE 16
typedef enum /**
{ * enum dmx_output - Output for the demux.
DMX_OUT_DECODER, /* Streaming directly to decoder. */ *
DMX_OUT_TAP, /* Output going to a memory buffer */ * @DMX_OUT_DECODER:
/* (to be retrieved via the read command).*/ * Streaming directly to decoder.
DMX_OUT_TS_TAP, /* Output multiplexed into a new TS */ * @DMX_OUT_TAP:
/* (to be retrieved by reading from the */ * Output going to a memory buffer (to be retrieved via the read command).
/* logical DVR device). */ * Delivers the stream output to the demux device on which the ioctl
DMX_OUT_TSDEMUX_TAP /* Like TS_TAP but retrieved from the DMX device */ * is called.
} dmx_output_t; * @DMX_OUT_TS_TAP:
* Output multiplexed into a new TS (to be retrieved by reading from the
* logical DVR device). Routes output to the logical DVR device
* ``/dev/dvb/adapter?/dvr?``, which delivers a TS multiplexed from all
* filters for which @DMX_OUT_TS_TAP was specified.
* @DMX_OUT_TSDEMUX_TAP:
* Like @DMX_OUT_TS_TAP but retrieved from the DMX device.
*/
enum dmx_output {
DMX_OUT_DECODER,
DMX_OUT_TAP,
DMX_OUT_TS_TAP,
DMX_OUT_TSDEMUX_TAP
};
typedef enum /**
{ * enum dmx_input - Input from the demux.
DMX_IN_FRONTEND, /* Input from a front-end device. */ *
DMX_IN_DVR /* Input from the logical DVR device. */ * @DMX_IN_FRONTEND: Input from a front-end device.
} dmx_input_t; * @DMX_IN_DVR: Input from the logical DVR device.
*/
enum dmx_input {
DMX_IN_FRONTEND,
DMX_IN_DVR
};
/**
* enum dmx_ts_pes - type of the PES filter.
*
* @DMX_PES_AUDIO0: first audio PID. Also referred as @DMX_PES_AUDIO.
* @DMX_PES_VIDEO0: first video PID. Also referred as @DMX_PES_VIDEO.
* @DMX_PES_TELETEXT0: first teletext PID. Also referred as @DMX_PES_TELETEXT.
* @DMX_PES_SUBTITLE0: first subtitle PID. Also referred as @DMX_PES_SUBTITLE.
* @DMX_PES_PCR0: first Program Clock Reference PID.
* Also referred as @DMX_PES_PCR.
*
* @DMX_PES_AUDIO1: second audio PID.
* @DMX_PES_VIDEO1: second video PID.
* @DMX_PES_TELETEXT1: second teletext PID.
* @DMX_PES_SUBTITLE1: second subtitle PID.
* @DMX_PES_PCR1: second Program Clock Reference PID.
*
* @DMX_PES_AUDIO2: third audio PID.
* @DMX_PES_VIDEO2: third video PID.
* @DMX_PES_TELETEXT2: third teletext PID.
* @DMX_PES_SUBTITLE2: third subtitle PID.
* @DMX_PES_PCR2: third Program Clock Reference PID.
*
* @DMX_PES_AUDIO3: fourth audio PID.
* @DMX_PES_VIDEO3: fourth video PID.
* @DMX_PES_TELETEXT3: fourth teletext PID.
* @DMX_PES_SUBTITLE3: fourth subtitle PID.
* @DMX_PES_PCR3: fourth Program Clock Reference PID.
*
* @DMX_PES_OTHER: any other PID.
*/
typedef enum dmx_ts_pes enum dmx_ts_pes {
{
DMX_PES_AUDIO0, DMX_PES_AUDIO0,
DMX_PES_VIDEO0, DMX_PES_VIDEO0,
DMX_PES_TELETEXT0, DMX_PES_TELETEXT0,
@ -78,7 +125,7 @@ typedef enum dmx_ts_pes
DMX_PES_PCR3, DMX_PES_PCR3,
DMX_PES_OTHER DMX_PES_OTHER
} dmx_pes_type_t; };
#define DMX_PES_AUDIO DMX_PES_AUDIO0 #define DMX_PES_AUDIO DMX_PES_AUDIO0
#define DMX_PES_VIDEO DMX_PES_VIDEO0 #define DMX_PES_VIDEO DMX_PES_VIDEO0
@ -87,69 +134,100 @@ typedef enum dmx_ts_pes
#define DMX_PES_PCR DMX_PES_PCR0 #define DMX_PES_PCR DMX_PES_PCR0
typedef struct dmx_filter
{ /**
* struct dmx_filter - Specifies a section header filter.
*
* @filter: bit array with bits to be matched at the section header.
* @mask: bits that are valid at the filter bit array.
* @mode: mode of match: if bit is zero, it will match if equal (positive
* match); if bit is one, it will match if the bit is negated.
*
* Note: All arrays in this struct have a size of DMX_FILTER_SIZE (16 bytes).
*/
struct dmx_filter {
__u8 filter[DMX_FILTER_SIZE]; __u8 filter[DMX_FILTER_SIZE];
__u8 mask[DMX_FILTER_SIZE]; __u8 mask[DMX_FILTER_SIZE];
__u8 mode[DMX_FILTER_SIZE]; __u8 mode[DMX_FILTER_SIZE];
} dmx_filter_t; };
/**
struct dmx_sct_filter_params * struct dmx_sct_filter_params - Specifies a section filter.
{ *
* @pid: PID to be filtered.
* @filter: section header filter, as defined by &struct dmx_filter.
* @timeout: maximum time to filter, in milliseconds.
* @flags: extra flags for the section filter.
*
* Carries the configuration for a MPEG-TS section filter.
*
* The @flags can be:
*
* - %DMX_CHECK_CRC - only deliver sections where the CRC check succeeded;
* - %DMX_ONESHOT - disable the section filter after one section
* has been delivered;
* - %DMX_IMMEDIATE_START - Start filter immediately without requiring a
* :ref:`DMX_START`.
*/
struct dmx_sct_filter_params {
__u16 pid; __u16 pid;
dmx_filter_t filter; struct dmx_filter filter;
__u32 timeout; __u32 timeout;
__u32 flags; __u32 flags;
#define DMX_CHECK_CRC 1 #define DMX_CHECK_CRC 1
#define DMX_ONESHOT 2 #define DMX_ONESHOT 2
#define DMX_IMMEDIATE_START 4 #define DMX_IMMEDIATE_START 4
#define DMX_KERNEL_CLIENT 0x8000
}; };
/**
struct dmx_pes_filter_params * struct dmx_pes_filter_params - Specifies Packetized Elementary Stream (PES)
{ * filter parameters.
*
* @pid: PID to be filtered.
* @input: Demux input, as specified by &enum dmx_input.
* @output: Demux output, as specified by &enum dmx_output.
* @pes_type: Type of the pes filter, as specified by &enum dmx_pes_type.
* @flags: Demux PES flags.
*/
struct dmx_pes_filter_params {
__u16 pid; __u16 pid;
dmx_input_t input; enum dmx_input input;
dmx_output_t output; enum dmx_output output;
dmx_pes_type_t pes_type; enum dmx_ts_pes pes_type;
__u32 flags; __u32 flags;
}; };
typedef struct dmx_caps { /**
__u32 caps; * struct dmx_stc - Stores System Time Counter (STC) information.
int num_decoders; *
} dmx_caps_t; * @num: input data: number of the STC, from 0 to N.
* @base: output: divisor for STC to get 90 kHz clock.
typedef enum { * @stc: output: stc in @base * 90 kHz units.
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;
struct dmx_stc { struct dmx_stc {
unsigned int num; /* input : which STC? 0..N */ unsigned int num;
unsigned int base; /* output: divisor for stc to get 90 kHz clock */ unsigned int base;
__u64 stc; /* output: stc in 'base'*90 kHz units */ __u64 stc;
}; };
#define DMX_START _IO('o', 41) #define DMX_START _IO('o', 41)
#define DMX_STOP _IO('o', 42) #define DMX_STOP _IO('o', 42)
#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params) #define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params)
#define DMX_SET_PES_FILTER _IOW('o', 44, struct dmx_pes_filter_params) #define DMX_SET_PES_FILTER _IOW('o', 44, struct dmx_pes_filter_params)
#define DMX_SET_BUFFER_SIZE _IO('o', 45) #define DMX_SET_BUFFER_SIZE _IO('o', 45)
#define DMX_GET_PES_PIDS _IOR('o', 47, __u16[5]) #define DMX_GET_PES_PIDS _IOR('o', 47, __u16[5])
#define DMX_GET_CAPS _IOR('o', 48, dmx_caps_t)
#define DMX_SET_SOURCE _IOW('o', 49, dmx_source_t)
#define DMX_GET_STC _IOWR('o', 50, struct dmx_stc) #define DMX_GET_STC _IOWR('o', 50, struct dmx_stc)
#define DMX_ADD_PID _IOW('o', 51, __u16) #define DMX_ADD_PID _IOW('o', 51, __u16)
#define DMX_REMOVE_PID _IOW('o', 52, __u16) #define DMX_REMOVE_PID _IOW('o', 52, __u16)
#if !defined(__KERNEL__)
/* This is needed for legacy userspace support */
typedef enum dmx_output dmx_output_t;
typedef enum dmx_input dmx_input_t;
typedef enum dmx_ts_pes dmx_pes_type_t;
typedef struct dmx_filter dmx_filter_t;
#endif
#endif /* _UAPI_DVBDMX_H_ */ #endif /* _UAPI_DVBDMX_H_ */

View File

@ -28,15 +28,47 @@
#include <linux/types.h> #include <linux/types.h>
typedef enum fe_type { /**
FE_QPSK, * enum fe_caps - Frontend capabilities
FE_QAM, *
FE_OFDM, * @FE_IS_STUPID: There's something wrong at the
FE_ATSC * frontend, and it can't report its
} fe_type_t; * capabilities.
* @FE_CAN_INVERSION_AUTO: Can auto-detect frequency spectral
* band inversion
typedef enum fe_caps { * @FE_CAN_FEC_1_2: Supports FEC 1/2
* @FE_CAN_FEC_2_3: Supports FEC 2/3
* @FE_CAN_FEC_3_4: Supports FEC 3/4
* @FE_CAN_FEC_4_5: Supports FEC 4/5
* @FE_CAN_FEC_5_6: Supports FEC 5/6
* @FE_CAN_FEC_6_7: Supports FEC 6/7
* @FE_CAN_FEC_7_8: Supports FEC 7/8
* @FE_CAN_FEC_8_9: Supports FEC 8/9
* @FE_CAN_FEC_AUTO: Can auto-detect FEC
* @FE_CAN_QPSK: Supports QPSK modulation
* @FE_CAN_QAM_16: Supports 16-QAM modulation
* @FE_CAN_QAM_32: Supports 32-QAM modulation
* @FE_CAN_QAM_64: Supports 64-QAM modulation
* @FE_CAN_QAM_128: Supports 128-QAM modulation
* @FE_CAN_QAM_256: Supports 256-QAM modulation
* @FE_CAN_QAM_AUTO: Can auto-detect QAM modulation
* @FE_CAN_TRANSMISSION_MODE_AUTO: Can auto-detect transmission mode
* @FE_CAN_BANDWIDTH_AUTO: Can auto-detect bandwidth
* @FE_CAN_GUARD_INTERVAL_AUTO: Can auto-detect guard interval
* @FE_CAN_HIERARCHY_AUTO: Can auto-detect hierarchy
* @FE_CAN_8VSB: Supports 8-VSB modulation
* @FE_CAN_16VSB: Supporta 16-VSB modulation
* @FE_HAS_EXTENDED_CAPS: Unused
* @FE_CAN_MULTISTREAM: Supports multistream filtering
* @FE_CAN_TURBO_FEC: Supports "turbo FEC" modulation
* @FE_CAN_2G_MODULATION: Supports "2nd generation" modulation,
* e. g. DVB-S2, DVB-T2, DVB-C2
* @FE_NEEDS_BENDING: Unused
* @FE_CAN_RECOVER: Can recover from a cable unplug
* automatically
* @FE_CAN_MUTE_TS: Can stop spurious TS data output
*/
enum fe_caps {
FE_IS_STUPID = 0, FE_IS_STUPID = 0,
FE_CAN_INVERSION_AUTO = 0x1, FE_CAN_INVERSION_AUTO = 0x1,
FE_CAN_FEC_1_2 = 0x2, FE_CAN_FEC_1_2 = 0x2,
@ -61,80 +93,163 @@ typedef enum fe_caps {
FE_CAN_HIERARCHY_AUTO = 0x100000, FE_CAN_HIERARCHY_AUTO = 0x100000,
FE_CAN_8VSB = 0x200000, FE_CAN_8VSB = 0x200000,
FE_CAN_16VSB = 0x400000, FE_CAN_16VSB = 0x400000,
FE_HAS_EXTENDED_CAPS = 0x800000, /* We need more bitspace for newer APIs, indicate this. */ FE_HAS_EXTENDED_CAPS = 0x800000,
FE_CAN_MULTISTREAM = 0x4000000, /* frontend supports multistream filtering */ FE_CAN_MULTISTREAM = 0x4000000,
FE_CAN_TURBO_FEC = 0x8000000, /* frontend supports "turbo fec modulation" */ FE_CAN_TURBO_FEC = 0x8000000,
FE_CAN_2G_MODULATION = 0x10000000, /* frontend supports "2nd generation modulation" (DVB-S2) */ FE_CAN_2G_MODULATION = 0x10000000,
FE_NEEDS_BENDING = 0x20000000, /* not supported anymore, don't use (frontend requires frequency bending) */ FE_NEEDS_BENDING = 0x20000000,
FE_CAN_RECOVER = 0x40000000, /* frontend can recover from a cable unplug automatically */ FE_CAN_RECOVER = 0x40000000,
FE_CAN_MUTE_TS = 0x80000000 /* frontend can stop spurious TS data output */ FE_CAN_MUTE_TS = 0x80000000
} fe_caps_t; };
/*
* DEPRECATED: Should be kept just due to backward compatibility.
*/
enum fe_type {
FE_QPSK,
FE_QAM,
FE_OFDM,
FE_ATSC
};
/**
* struct dvb_frontend_info - Frontend properties and capabilities
*
* @name: Name of the frontend
* @type: **DEPRECATED**.
* Should not be used on modern programs,
* as a frontend may have more than one type.
* In order to get the support types of a given
* frontend, use :c:type:`DTV_ENUM_DELSYS`
* instead.
* @frequency_min: Minimal frequency supported by the frontend.
* @frequency_max: Minimal frequency supported by the frontend.
* @frequency_stepsize: All frequencies are multiple of this value.
* @frequency_tolerance: Frequency tolerance.
* @symbol_rate_min: Minimal symbol rate, in bauds
* (for Cable/Satellite systems).
* @symbol_rate_max: Maximal symbol rate, in bauds
* (for Cable/Satellite systems).
* @symbol_rate_tolerance: Maximal symbol rate tolerance, in ppm
* (for Cable/Satellite systems).
* @notifier_delay: **DEPRECATED**. Not used by any driver.
* @caps: Capabilities supported by the frontend,
* as specified in &enum fe_caps.
*
* .. note:
*
* #. The frequencies are specified in Hz for Terrestrial and Cable
* systems.
* #. The frequencies are specified in kHz for Satellite systems.
*/
struct dvb_frontend_info { struct dvb_frontend_info {
char name[128]; char name[128];
fe_type_t type; /* DEPRECATED. Use DTV_ENUM_DELSYS instead */ enum fe_type type; /* DEPRECATED. Use DTV_ENUM_DELSYS instead */
__u32 frequency_min; __u32 frequency_min;
__u32 frequency_max; __u32 frequency_max;
__u32 frequency_stepsize; __u32 frequency_stepsize;
__u32 frequency_tolerance; __u32 frequency_tolerance;
__u32 symbol_rate_min; __u32 symbol_rate_min;
__u32 symbol_rate_max; __u32 symbol_rate_max;
__u32 symbol_rate_tolerance; /* ppm */ __u32 symbol_rate_tolerance;
__u32 notifier_delay; /* DEPRECATED */ __u32 notifier_delay; /* DEPRECATED */
fe_caps_t caps; enum fe_caps caps;
}; };
/** /**
* struct dvb_diseqc_master_cmd - DiSEqC master command
*
* @msg:
* DiSEqC message to be sent. It contains a 3 bytes header with:
* framing + address + command, and an optional argument
* of up to 3 bytes of data.
* @msg_len:
* Length of the DiSEqC message. Valid values are 3 to 6.
*
* Check out the DiSEqC bus spec available on http://www.eutelsat.org/ for * Check out the DiSEqC bus spec available on http://www.eutelsat.org/ for
* the meaning of this struct... * the possible messages that can be used.
*/ */
struct dvb_diseqc_master_cmd { struct dvb_diseqc_master_cmd {
__u8 msg [6]; /* { framing, address, command, data [3] } */ __u8 msg[6];
__u8 msg_len; /* valid values are 3...6 */ __u8 msg_len;
}; };
/**
* struct dvb_diseqc_slave_reply - DiSEqC received data
*
* @msg:
* DiSEqC message buffer to store a message received via DiSEqC.
* It contains one byte header with: framing and
* an optional argument of up to 3 bytes of data.
* @msg_len:
* Length of the DiSEqC message. Valid values are 0 to 4,
* where 0 means no message.
* @timeout:
* Return from ioctl after timeout ms with errorcode when
* no message was received.
*
* Check out the DiSEqC bus spec available on http://www.eutelsat.org/ for
* the possible messages that can be used.
*/
struct dvb_diseqc_slave_reply { struct dvb_diseqc_slave_reply {
__u8 msg [4]; /* { framing, data [3] } */ __u8 msg[4];
__u8 msg_len; /* valid values are 0...4, 0 means no msg */ __u8 msg_len;
int timeout; /* return from ioctl after timeout ms with */ int timeout;
}; /* errorcode when no message was received */ };
/**
typedef enum fe_sec_voltage { * enum fe_sec_voltage - DC Voltage used to feed the LNBf
*
* @SEC_VOLTAGE_13: Output 13V to the LNBf
* @SEC_VOLTAGE_18: Output 18V to the LNBf
* @SEC_VOLTAGE_OFF: Don't feed the LNBf with a DC voltage
*/
enum fe_sec_voltage {
SEC_VOLTAGE_13, SEC_VOLTAGE_13,
SEC_VOLTAGE_18, SEC_VOLTAGE_18,
SEC_VOLTAGE_OFF 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;
/** /**
* enum fe_status - enumerates the possible frontend status * enum fe_sec_tone_mode - Type of tone to be send to the LNBf.
* @FE_HAS_SIGNAL: found something above the noise level * @SEC_TONE_ON: Sends a 22kHz tone burst to the antenna.
* @FE_HAS_CARRIER: found a DVB signal * @SEC_TONE_OFF: Don't send a 22kHz tone to the antenna (except
* @FE_HAS_VITERBI: FEC is stable * if the ``FE_DISEQC_*`` ioctls are called).
* @FE_HAS_SYNC: found sync bytes
* @FE_HAS_LOCK: everything's working
* @FE_TIMEDOUT: no lock within the last ~2 seconds
* @FE_REINIT: frontend was reinitialized, application is recommended
* to reset DiSEqC, tone and parameters
*/ */
enum fe_sec_tone_mode {
SEC_TONE_ON,
SEC_TONE_OFF
};
typedef enum fe_status { /**
* enum fe_sec_mini_cmd - Type of mini burst to be sent
*
* @SEC_MINI_A: Sends a mini-DiSEqC 22kHz '0' Tone Burst to select
* satellite-A
* @SEC_MINI_B: Sends a mini-DiSEqC 22kHz '1' Data Burst to select
* satellite-B
*/
enum fe_sec_mini_cmd {
SEC_MINI_A,
SEC_MINI_B
};
/**
* enum fe_status - Enumerates the possible frontend status.
* @FE_NONE: The frontend doesn't have any kind of lock.
* That's the initial frontend status
* @FE_HAS_SIGNAL: Has found something above the noise level.
* @FE_HAS_CARRIER: Has found a signal.
* @FE_HAS_VITERBI: FEC inner coding (Viterbi, LDPC or other inner code).
* is stable.
* @FE_HAS_SYNC: Synchronization bytes was found.
* @FE_HAS_LOCK: Digital TV were locked and everything is working.
* @FE_TIMEDOUT: Fo lock within the last about 2 seconds.
* @FE_REINIT: Frontend was reinitialized, application is recommended
* to reset DiSEqC, tone and parameters.
*/
enum fe_status {
FE_NONE = 0x00,
FE_HAS_SIGNAL = 0x01, FE_HAS_SIGNAL = 0x01,
FE_HAS_CARRIER = 0x02, FE_HAS_CARRIER = 0x02,
FE_HAS_VITERBI = 0x04, FE_HAS_VITERBI = 0x04,
@ -142,16 +257,48 @@ typedef enum fe_status {
FE_HAS_LOCK = 0x10, FE_HAS_LOCK = 0x10,
FE_TIMEDOUT = 0x20, FE_TIMEDOUT = 0x20,
FE_REINIT = 0x40, FE_REINIT = 0x40,
} fe_status_t; };
typedef enum fe_spectral_inversion { /**
* enum fe_spectral_inversion - Type of inversion band
*
* @INVERSION_OFF: Don't do spectral band inversion.
* @INVERSION_ON: Do spectral band inversion.
* @INVERSION_AUTO: Autodetect spectral band inversion.
*
* This parameter 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. If the hardware doesn't
* support, the %dvb_frontend will try to lock at the carrier first with
* inversion off. If it fails, it will try to enable inversion.
*/
enum fe_spectral_inversion {
INVERSION_OFF, INVERSION_OFF,
INVERSION_ON, INVERSION_ON,
INVERSION_AUTO INVERSION_AUTO
} fe_spectral_inversion_t; };
/**
typedef enum fe_code_rate { * enum fe_code_rate - Type of Forward Error Correction (FEC)
*
*
* @FEC_NONE: No Forward Error Correction Code
* @FEC_1_2: Forward Error Correction Code 1/2
* @FEC_2_3: Forward Error Correction Code 2/3
* @FEC_3_4: Forward Error Correction Code 3/4
* @FEC_4_5: Forward Error Correction Code 4/5
* @FEC_5_6: Forward Error Correction Code 5/6
* @FEC_6_7: Forward Error Correction Code 6/7
* @FEC_7_8: Forward Error Correction Code 7/8
* @FEC_8_9: Forward Error Correction Code 8/9
* @FEC_AUTO: Autodetect Error Correction Code
* @FEC_3_5: Forward Error Correction Code 3/5
* @FEC_9_10: Forward Error Correction Code 9/10
* @FEC_2_5: Forward Error Correction Code 2/5
*
* Please note that not all FEC types are supported by a given standard.
*/
enum fe_code_rate {
FEC_NONE = 0, FEC_NONE = 0,
FEC_1_2, FEC_1_2,
FEC_2_3, FEC_2_3,
@ -167,10 +314,29 @@ typedef enum fe_code_rate {
FEC_2_5, FEC_2_5,
FEC_1_4, FEC_1_4,
FEC_1_3, FEC_1_3,
} fe_code_rate_t; };
/**
typedef enum fe_modulation { * enum fe_modulation - Type of modulation/constellation
* @QPSK: QPSK modulation
* @QAM_16: 16-QAM modulation
* @QAM_32: 32-QAM modulation
* @QAM_64: 64-QAM modulation
* @QAM_128: 128-QAM modulation
* @QAM_256: 256-QAM modulation
* @QAM_AUTO: Autodetect QAM modulation
* @VSB_8: 8-VSB modulation
* @VSB_16: 16-VSB modulation
* @PSK_8: 8-PSK modulation
* @APSK_16: 16-APSK modulation
* @APSK_32: 32-APSK modulation
* @DQPSK: DQPSK modulation
* @QAM_4_NR: 4-QAM-NR modulation
*
* Please note that not all modulations are supported by a given standard.
*
*/
enum fe_modulation {
QPSK, QPSK,
QAM_16, QAM_16,
QAM_32, QAM_32,
@ -185,9 +351,35 @@ typedef enum fe_modulation {
APSK_32, APSK_32,
DQPSK, DQPSK,
QAM_4_NR, QAM_4_NR,
} fe_modulation_t; };
typedef enum fe_transmit_mode { /**
* enum fe_transmit_mode - Transmission mode
*
* @TRANSMISSION_MODE_AUTO:
* Autodetect transmission mode. The hardware will try to find the
* correct FFT-size (if capable) to fill in the missing parameters.
* @TRANSMISSION_MODE_1K:
* Transmission mode 1K
* @TRANSMISSION_MODE_2K:
* Transmission mode 2K
* @TRANSMISSION_MODE_8K:
* Transmission mode 8K
* @TRANSMISSION_MODE_4K:
* Transmission mode 4K
* @TRANSMISSION_MODE_16K:
* Transmission mode 16K
* @TRANSMISSION_MODE_32K:
* Transmission mode 32K
* @TRANSMISSION_MODE_C1:
* Single Carrier (C=1) transmission mode (DTMB only)
* @TRANSMISSION_MODE_C3780:
* Multi Carrier (C=3780) transmission mode (DTMB only)
*
* Please note that not all transmission modes are supported by a given
* standard.
*/
enum fe_transmit_mode {
TRANSMISSION_MODE_2K, TRANSMISSION_MODE_2K,
TRANSMISSION_MODE_8K, TRANSMISSION_MODE_8K,
TRANSMISSION_MODE_AUTO, TRANSMISSION_MODE_AUTO,
@ -198,21 +390,26 @@ typedef enum fe_transmit_mode {
TRANSMISSION_MODE_C1, TRANSMISSION_MODE_C1,
TRANSMISSION_MODE_C3780, TRANSMISSION_MODE_C3780,
TRANSMISSION_MODE_64K, TRANSMISSION_MODE_64K,
} fe_transmit_mode_t; };
#if defined(__DVB_CORE__) || !defined (__KERNEL__) /**
typedef enum fe_bandwidth { * enum fe_guard_interval - Guard interval
BANDWIDTH_8_MHZ, *
BANDWIDTH_7_MHZ, * @GUARD_INTERVAL_AUTO: Autodetect the guard interval
BANDWIDTH_6_MHZ, * @GUARD_INTERVAL_1_128: Guard interval 1/128
BANDWIDTH_AUTO, * @GUARD_INTERVAL_1_32: Guard interval 1/32
BANDWIDTH_5_MHZ, * @GUARD_INTERVAL_1_16: Guard interval 1/16
BANDWIDTH_10_MHZ, * @GUARD_INTERVAL_1_8: Guard interval 1/8
BANDWIDTH_1_712_MHZ, * @GUARD_INTERVAL_1_4: Guard interval 1/4
} fe_bandwidth_t; * @GUARD_INTERVAL_19_128: Guard interval 19/128
#endif * @GUARD_INTERVAL_19_256: Guard interval 19/256
* @GUARD_INTERVAL_PN420: PN length 420 (1/4)
typedef enum fe_guard_interval { * @GUARD_INTERVAL_PN595: PN length 595 (1/6)
* @GUARD_INTERVAL_PN945: PN length 945 (1/9)
*
* Please note that not all guard intervals are supported by a given standard.
*/
enum fe_guard_interval {
GUARD_INTERVAL_1_32, GUARD_INTERVAL_1_32,
GUARD_INTERVAL_1_16, GUARD_INTERVAL_1_16,
GUARD_INTERVAL_1_8, GUARD_INTERVAL_1_8,
@ -224,17 +421,35 @@ typedef enum fe_guard_interval {
GUARD_INTERVAL_PN420, GUARD_INTERVAL_PN420,
GUARD_INTERVAL_PN595, GUARD_INTERVAL_PN595,
GUARD_INTERVAL_PN945, GUARD_INTERVAL_PN945,
} fe_guard_interval_t; };
/**
typedef enum fe_hierarchy { * enum fe_hierarchy - Hierarchy
* @HIERARCHY_NONE: No hierarchy
* @HIERARCHY_AUTO: Autodetect hierarchy (if supported)
* @HIERARCHY_1: Hierarchy 1
* @HIERARCHY_2: Hierarchy 2
* @HIERARCHY_4: Hierarchy 4
*
* Please note that not all hierarchy types are supported by a given standard.
*/
enum fe_hierarchy {
HIERARCHY_NONE, HIERARCHY_NONE,
HIERARCHY_1, HIERARCHY_1,
HIERARCHY_2, HIERARCHY_2,
HIERARCHY_4, HIERARCHY_4,
HIERARCHY_AUTO HIERARCHY_AUTO
} fe_hierarchy_t; };
/**
* enum fe_interleaving - Interleaving
* @INTERLEAVING_NONE: No interleaving.
* @INTERLEAVING_AUTO: Auto-detect interleaving.
* @INTERLEAVING_240: Interleaving of 240 symbols.
* @INTERLEAVING_720: Interleaving of 720 symbols.
*
* Please note that, currently, only DTMB uses it.
*/
enum fe_interleaving { enum fe_interleaving {
INTERLEAVING_NONE, INTERLEAVING_NONE,
INTERLEAVING_AUTO, INTERLEAVING_AUTO,
@ -242,52 +457,8 @@ enum fe_interleaving {
INTERLEAVING_720, INTERLEAVING_720,
}; };
#if defined(__DVB_CORE__) || !defined (__KERNEL__) /* DVBv5 property Commands */
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;
};
#endif
/* S2API Commands */
#define DTV_UNDEFINED 0 #define DTV_UNDEFINED 0
#define DTV_TUNE 1 #define DTV_TUNE 1
#define DTV_CLEAR 2 #define DTV_CLEAR 2
@ -383,20 +554,80 @@ struct dvb_frontend_event {
#define DTV_MAX_COMMAND DTV_PLS #define DTV_MAX_COMMAND DTV_PLS
typedef enum fe_pilot { /**
* enum fe_pilot - Type of pilot tone
*
* @PILOT_ON: Pilot tones enabled
* @PILOT_OFF: Pilot tones disabled
* @PILOT_AUTO: Autodetect pilot tones
*/
enum fe_pilot {
PILOT_ON, PILOT_ON,
PILOT_OFF, PILOT_OFF,
PILOT_AUTO, PILOT_AUTO,
} fe_pilot_t; };
typedef enum fe_rolloff { /**
ROLLOFF_35, /* Implied value in DVB-S, default for DVB-S2 */ * enum fe_rolloff - Rolloff factor
* @ROLLOFF_35: Roloff factor: α=35%
* @ROLLOFF_20: Roloff factor: α=20%
* @ROLLOFF_25: Roloff factor: α=25%
* @ROLLOFF_AUTO: Auto-detect the roloff factor.
*
* .. note:
*
* Roloff factor of 35% is implied on DVB-S. On DVB-S2, it is default.
*/
enum fe_rolloff {
ROLLOFF_35,
ROLLOFF_20, ROLLOFF_20,
ROLLOFF_25, ROLLOFF_25,
ROLLOFF_AUTO, ROLLOFF_AUTO,
} fe_rolloff_t; };
typedef enum fe_delivery_system { /**
* enum fe_delivery_system - Type of the delivery system
*
* @SYS_UNDEFINED:
* Undefined standard. Generally, indicates an error
* @SYS_DVBC_ANNEX_A:
* Cable TV: DVB-C following ITU-T J.83 Annex A spec
* @SYS_DVBC_ANNEX_B:
* Cable TV: DVB-C following ITU-T J.83 Annex B spec (ClearQAM)
* @SYS_DVBC_ANNEX_C:
* Cable TV: DVB-C following ITU-T J.83 Annex C spec
* @SYS_ISDBC:
* Cable TV: ISDB-C (no drivers yet)
* @SYS_DVBT:
* Terrestrial TV: DVB-T
* @SYS_DVBT2:
* Terrestrial TV: DVB-T2
* @SYS_ISDBT:
* Terrestrial TV: ISDB-T
* @SYS_ATSC:
* Terrestrial TV: ATSC
* @SYS_ATSCMH:
* Terrestrial TV (mobile): ATSC-M/H
* @SYS_DTMB:
* Terrestrial TV: DTMB
* @SYS_DVBS:
* Satellite TV: DVB-S
* @SYS_DVBS2:
* Satellite TV: DVB-S2
* @SYS_TURBO:
* Satellite TV: DVB-S Turbo
* @SYS_ISDBS:
* Satellite TV: ISDB-S
* @SYS_DAB:
* Digital audio: DAB (not fully supported)
* @SYS_DSS:
* Satellite TV: DSS (not fully supported)
* @SYS_CMMB:
* Terrestrial TV (mobile): CMMB (not fully supported)
* @SYS_DVBH:
* Terrestrial TV (mobile): DVB-H (standard deprecated)
*/
enum fe_delivery_system {
SYS_UNDEFINED, SYS_UNDEFINED,
SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_A,
SYS_DVBC_ANNEX_B, SYS_DVBC_ANNEX_B,
@ -417,37 +648,87 @@ typedef enum fe_delivery_system {
SYS_TURBO, SYS_TURBO,
SYS_DVBC_ANNEX_C, SYS_DVBC_ANNEX_C,
SYS_DVBC2, SYS_DVBC2,
} fe_delivery_system_t; };
/* backward compatibility */ /* backward compatibility definitions for delivery systems */
#define SYS_DVBC_ANNEX_AC SYS_DVBC_ANNEX_A #define SYS_DVBC_ANNEX_AC SYS_DVBC_ANNEX_A
#define SYS_DMBTH SYS_DTMB /* DMB-TH is legacy name, use DTMB instead */ #define SYS_DMBTH SYS_DTMB /* DMB-TH is legacy name, use DTMB */
/* ATSC-MH */ /* ATSC-MH specific parameters */
/**
* enum atscmh_sccc_block_mode - Type of Series Concatenated Convolutional
* Code Block Mode.
*
* @ATSCMH_SCCC_BLK_SEP:
* Separate SCCC: the SCCC outer code mode shall be set independently
* for each Group Region (A, B, C, D)
* @ATSCMH_SCCC_BLK_COMB:
* Combined SCCC: all four Regions shall have the same SCCC outer
* code mode.
* @ATSCMH_SCCC_BLK_RES:
* Reserved. Shouldn't be used.
*/
enum atscmh_sccc_block_mode { enum atscmh_sccc_block_mode {
ATSCMH_SCCC_BLK_SEP = 0, ATSCMH_SCCC_BLK_SEP = 0,
ATSCMH_SCCC_BLK_COMB = 1, ATSCMH_SCCC_BLK_COMB = 1,
ATSCMH_SCCC_BLK_RES = 2, ATSCMH_SCCC_BLK_RES = 2,
}; };
/**
* enum atscmh_sccc_code_mode - Type of Series Concatenated Convolutional
* Code Rate.
*
* @ATSCMH_SCCC_CODE_HLF:
* The outer code rate of a SCCC Block is 1/2 rate.
* @ATSCMH_SCCC_CODE_QTR:
* The outer code rate of a SCCC Block is 1/4 rate.
* @ATSCMH_SCCC_CODE_RES:
* Reserved. Should not be used.
*/
enum atscmh_sccc_code_mode { enum atscmh_sccc_code_mode {
ATSCMH_SCCC_CODE_HLF = 0, ATSCMH_SCCC_CODE_HLF = 0,
ATSCMH_SCCC_CODE_QTR = 1, ATSCMH_SCCC_CODE_QTR = 1,
ATSCMH_SCCC_CODE_RES = 2, ATSCMH_SCCC_CODE_RES = 2,
}; };
/**
* enum atscmh_rs_frame_ensemble - Reed Solomon(RS) frame ensemble.
*
* @ATSCMH_RSFRAME_ENS_PRI: Primary Ensemble.
* @ATSCMH_RSFRAME_ENS_SEC: Secondary Ensemble.
*/
enum atscmh_rs_frame_ensemble { enum atscmh_rs_frame_ensemble {
ATSCMH_RSFRAME_ENS_PRI = 0, ATSCMH_RSFRAME_ENS_PRI = 0,
ATSCMH_RSFRAME_ENS_SEC = 1, ATSCMH_RSFRAME_ENS_SEC = 1,
}; };
/**
* enum atscmh_rs_frame_mode - Reed Solomon (RS) frame mode.
*
* @ATSCMH_RSFRAME_PRI_ONLY:
* Single Frame: There is only a primary RS Frame for all Group
* Regions.
* @ATSCMH_RSFRAME_PRI_SEC:
* Dual Frame: There are two separate RS Frames: Primary RS Frame for
* Group Region A and B and Secondary RS Frame for Group Region C and
* D.
* @ATSCMH_RSFRAME_RES:
* Reserved. Shouldn't be used.
*/
enum atscmh_rs_frame_mode { enum atscmh_rs_frame_mode {
ATSCMH_RSFRAME_PRI_ONLY = 0, ATSCMH_RSFRAME_PRI_ONLY = 0,
ATSCMH_RSFRAME_PRI_SEC = 1, ATSCMH_RSFRAME_PRI_SEC = 1,
ATSCMH_RSFRAME_RES = 2, ATSCMH_RSFRAME_RES = 2,
}; };
/**
* enum atscmh_rs_code_mode
* @ATSCMH_RSCODE_211_187: Reed Solomon code (211,187).
* @ATSCMH_RSCODE_223_187: Reed Solomon code (223,187).
* @ATSCMH_RSCODE_235_187: Reed Solomon code (235,187).
* @ATSCMH_RSCODE_RES: Reserved. Shouldn't be used.
*/
enum atscmh_rs_code_mode { enum atscmh_rs_code_mode {
ATSCMH_RSCODE_211_187 = 0, ATSCMH_RSCODE_211_187 = 0,
ATSCMH_RSCODE_223_187 = 1, ATSCMH_RSCODE_223_187 = 1,
@ -459,23 +740,13 @@ enum atscmh_rs_code_mode {
#define NO_SCRAMBLING_CODE (~0U) #define NO_SCRAMBLING_CODE (~0U)
#define LNA_AUTO (~0U) #define LNA_AUTO (~0U)
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 */
};
/** /**
* Scale types for the quality parameters. * enum fecap_scale_params - scale types for the quality parameters.
*
* @FE_SCALE_NOT_AVAILABLE: That QoS measure is not available. That * @FE_SCALE_NOT_AVAILABLE: That QoS measure is not available. That
* could indicate a temporary or a permanent * could indicate a temporary or a permanent
* condition. * condition.
* @FE_SCALE_DECIBEL: The scale is measured in 0.0001 dB steps, typically * @FE_SCALE_DECIBEL: The scale is measured in 0.001 dB steps, typically
* used on signal measures. * used on signal measures.
* @FE_SCALE_RELATIVE: The scale is a relative percentual measure, * @FE_SCALE_RELATIVE: The scale is a relative percentual measure,
* ranging from 0 (0%) to 0xffff (100%). * ranging from 0 (0%) to 0xffff (100%).
@ -492,50 +763,92 @@ enum fecap_scale_params {
/** /**
* struct dtv_stats - Used for reading a DTV status property * struct dtv_stats - Used for reading a DTV status property
* *
* @value: value of the measure. Should range from 0 to 0xffff;
* @scale: Filled with enum fecap_scale_params - the scale * @scale: Filled with enum fecap_scale_params - the scale
* in usage for that parameter * in usage for that parameter
* *
* The ``{unnamed_union}`` may have either one of the values below:
*
* %svalue
* integer value of the measure, for %FE_SCALE_DECIBEL,
* used for dB measures. The unit is 0.001 dB.
*
* %uvalue
* unsigned integer value of the measure, used when @scale is
* either %FE_SCALE_RELATIVE or %FE_SCALE_COUNTER.
*
* For most delivery systems, this will return a single value for each * For most delivery systems, this will return a single value for each
* parameter. * parameter.
*
* It should be noticed, however, that new OFDM delivery systems like * It should be noticed, however, that new OFDM delivery systems like
* ISDB can use different modulation types for each group of carriers. * ISDB can use different modulation types for each group of carriers.
* On such standards, up to 8 groups of statistics can be provided, one * On such standards, up to 8 groups of statistics can be provided, one
* for each carrier group (called "layer" on ISDB). * for each carrier group (called "layer" on ISDB).
*
* In order to be consistent with other delivery systems, the first * In order to be consistent with other delivery systems, the first
* value refers to the entire set of carriers ("global"). * value refers to the entire set of carriers ("global").
* dtv_status:scale should use the value FE_SCALE_NOT_AVAILABLE when *
* @scale should use the value %FE_SCALE_NOT_AVAILABLE when
* the value for the entire group of carriers or from one specific layer * the value for the entire group of carriers or from one specific layer
* is not provided by the hardware. * is not provided by the hardware.
* st.len should be filled with the latest filled status + 1.
* *
* In other words, for ISDB, those values should be filled like: * @len should be filled with the latest filled status + 1.
*
* In other words, for ISDB, those values should be filled like::
*
* u.st.stat.svalue[0] = global statistics; * u.st.stat.svalue[0] = global statistics;
* u.st.stat.scale[0] = FE_SCALE_DECIBELS; * u.st.stat.scale[0] = FE_SCALE_DECIBEL;
* u.st.stat.value[1] = layer A statistics; * u.st.stat.value[1] = layer A statistics;
* u.st.stat.scale[1] = FE_SCALE_NOT_AVAILABLE (if not available); * u.st.stat.scale[1] = FE_SCALE_NOT_AVAILABLE (if not available);
* u.st.stat.svalue[2] = layer B statistics; * u.st.stat.svalue[2] = layer B statistics;
* u.st.stat.scale[2] = FE_SCALE_DECIBELS; * u.st.stat.scale[2] = FE_SCALE_DECIBEL;
* u.st.stat.svalue[3] = layer C statistics; * u.st.stat.svalue[3] = layer C statistics;
* u.st.stat.scale[3] = FE_SCALE_DECIBELS; * u.st.stat.scale[3] = FE_SCALE_DECIBEL;
* u.st.len = 4; * u.st.len = 4;
*/ */
struct dtv_stats { struct dtv_stats {
__u8 scale; /* enum fecap_scale_params type */ __u8 scale; /* enum fecap_scale_params type */
union { union {
__u64 uvalue; /* for counters and relative scales */ __u64 uvalue; /* for counters and relative scales */
__s64 svalue; /* for 0.0001 dB measures */ __s64 svalue; /* for 0.001 dB measures */
}; };
} __attribute__ ((packed)); } __attribute__ ((packed));
#define MAX_DTV_STATS 4 #define MAX_DTV_STATS 4
/**
* struct dtv_fe_stats - store Digital TV frontend statistics
*
* @len: length of the statistics - if zero, stats is disabled.
* @stat: array with digital TV statistics.
*
* On most standards, @len can either be 0 or 1. However, for ISDB, each
* layer is modulated in separate. So, each layer may have its own set
* of statistics. If so, stat[0] carries on a global value for the property.
* Indexes 1 to 3 means layer A to B.
*/
struct dtv_fe_stats { struct dtv_fe_stats {
__u8 len; __u8 len;
struct dtv_stats stat[MAX_DTV_STATS]; struct dtv_stats stat[MAX_DTV_STATS];
} __attribute__ ((packed)); } __attribute__ ((packed));
/**
* struct dtv_property - store one of frontend command and its value
*
* @cmd: Digital TV command.
* @reserved: Not used.
* @u: Union with the values for the command.
* @result: Result of the command set (currently unused).
*
* The @u union may have either one of the values below:
*
* %data
* an unsigned 32-bits number.
* %st
* a &struct dtv_fe_stats array of statistics.
* %buffer
* a buffer of up to 32 characters (currently unused).
*/
struct dtv_property { struct dtv_property {
__u32 cmd; __u32 cmd;
__u32 reserved[3]; __u32 reserved[3];
@ -555,24 +868,27 @@ struct dtv_property {
/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */ /* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */
#define DTV_IOCTL_MAX_MSGS 64 #define DTV_IOCTL_MAX_MSGS 64
/**
* struct dtv_properties - a set of command/value pairs.
*
* @num: amount of commands stored at the struct.
* @props: a pointer to &struct dtv_property.
*/
struct dtv_properties { struct dtv_properties {
__u32 num; __u32 num;
struct dtv_property *props; 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 * When set, this flag will disable any zigzagging or other "normal" tuning
* behaviour. Additionally, there will be no automatic monitoring of the lock * behavior. Additionally, there will be no automatic monitoring of the lock
* status, and hence no frontend events will be generated. If a frontend device * 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 * is closed, this flag will be automatically turned off when the device is
* reopened read-write. * reopened read-write.
*/ */
#define FE_TUNE_MODE_ONESHOT 0x01 #define FE_TUNE_MODE_ONESHOT 0x01
/* Digital TV Frontend API calls */
#define FE_GET_INFO _IOR('o', 61, struct dvb_frontend_info) #define FE_GET_INFO _IOR('o', 61, struct dvb_frontend_info)
@ -591,11 +907,110 @@ struct dtv_properties {
#define FE_READ_SNR _IOR('o', 72, __u16) #define FE_READ_SNR _IOR('o', 72, __u16)
#define FE_READ_UNCORRECTED_BLOCKS _IOR('o', 73, __u32) #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_SET_FRONTEND_TUNE_MODE _IO('o', 81) /* unsigned int */
#define FE_GET_EVENT _IOR('o', 78, struct dvb_frontend_event) #define FE_GET_EVENT _IOR('o', 78, struct dvb_frontend_event)
#define FE_DISHNETWORK_SEND_LEGACY_CMD _IO('o', 80) /* unsigned int */ #define FE_DISHNETWORK_SEND_LEGACY_CMD _IO('o', 80) /* unsigned int */
#define FE_SET_PROPERTY _IOW('o', 82, struct dtv_properties)
#define FE_GET_PROPERTY _IOR('o', 83, struct dtv_properties)
#if defined(__DVB_CORE__) || !defined(__KERNEL__)
/*
* DEPRECATED: Everything below is deprecated in favor of DVBv5 API
*
* The DVBv3 only ioctls, structs and enums should not be used on
* newer programs, as it doesn't support the second generation of
* digital TV standards, nor supports newer delivery systems.
* They also don't support modern frontends with usually support multiple
* delivery systems.
*
* Drivers shouldn't use them.
*
* New applications should use DVBv5 delivery system instead
*/
/*
*/
enum fe_bandwidth {
BANDWIDTH_8_MHZ,
BANDWIDTH_7_MHZ,
BANDWIDTH_6_MHZ,
BANDWIDTH_AUTO,
BANDWIDTH_5_MHZ,
BANDWIDTH_10_MHZ,
BANDWIDTH_1_712_MHZ,
};
/* This is kept for legacy userspace support */
typedef enum fe_sec_voltage fe_sec_voltage_t;
typedef enum fe_caps fe_caps_t;
typedef enum fe_type fe_type_t;
typedef enum fe_sec_tone_mode fe_sec_tone_mode_t;
typedef enum fe_sec_mini_cmd fe_sec_mini_cmd_t;
typedef enum fe_status fe_status_t;
typedef enum fe_spectral_inversion fe_spectral_inversion_t;
typedef enum fe_code_rate fe_code_rate_t;
typedef enum fe_modulation fe_modulation_t;
typedef enum fe_transmit_mode fe_transmit_mode_t;
typedef enum fe_bandwidth fe_bandwidth_t;
typedef enum fe_guard_interval fe_guard_interval_t;
typedef enum fe_hierarchy fe_hierarchy_t;
typedef enum fe_pilot fe_pilot_t;
typedef enum fe_rolloff fe_rolloff_t;
typedef enum fe_delivery_system fe_delivery_system_t;
/* DVBv3 structs */
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 DVB-C/DVB-T/ATSC */
/* intermediate frequency in kHz for DVB-S */
fe_spectral_inversion_t inversion;
union {
struct dvb_qpsk_parameters qpsk; /* DVB-S */
struct dvb_qam_parameters qam; /* DVB-C */
struct dvb_ofdm_parameters ofdm; /* DVB-T */
struct dvb_vsb_parameters vsb; /* ATSC */
} u;
};
struct dvb_frontend_event {
fe_status_t status;
struct dvb_frontend_parameters parameters;
};
/* DVBv3 API calls */
#define FE_SET_FRONTEND _IOW('o', 76, struct dvb_frontend_parameters)
#define FE_GET_FRONTEND _IOR('o', 77, struct dvb_frontend_parameters)
#endif
#endif /*_DVBFRONTEND_H_*/ #endif /*_DVBFRONTEND_H_*/

View File

@ -26,6 +26,21 @@
#include <linux/types.h> #include <linux/types.h>
/**
* struct dvb_net_if - describes a DVB network interface
*
* @pid: Packet ID (PID) of the MPEG-TS that contains data
* @if_num: number of the Digital TV interface.
* @feedtype: Encapsulation type of the feed.
*
* A MPEG-TS stream may contain packet IDs with IP packages on it.
* This struct describes it, and the type of encoding.
*
* @feedtype can be:
*
* - %DVB_NET_FEEDTYPE_MPE for MPE encoding
* - %DVB_NET_FEEDTYPE_ULE for ULE encoding.
*/
struct dvb_net_if { struct dvb_net_if {
__u16 pid; __u16 pid;
__u16 if_num; __u16 if_num;

View File

@ -26,7 +26,6 @@
#include <linux/types.h> #include <linux/types.h>
#ifndef __KERNEL__ #ifndef __KERNEL__
#include <stdint.h>
#include <time.h> #include <time.h>
#endif #endif
@ -139,7 +138,8 @@ struct video_event {
#define VIDEO_EVENT_FRAME_RATE_CHANGED 2 #define VIDEO_EVENT_FRAME_RATE_CHANGED 2
#define VIDEO_EVENT_DECODER_STOPPED 3 #define VIDEO_EVENT_DECODER_STOPPED 3
#define VIDEO_EVENT_VSYNC 4 #define VIDEO_EVENT_VSYNC 4
__kernel_time_t timestamp; /* unused, make sure to use atomic time for y2038 if it ever gets used */
long timestamp;
union { union {
video_size_t size; video_size_t size;
unsigned int frame_rate; /* in frames per 1000sec */ unsigned int frame_rate; /* in frames per 1000sec */
@ -211,7 +211,8 @@ typedef __u16 video_attributes_t;
/* 6 line 21-2 data present in GOP (1=yes, 0=no) */ /* 6 line 21-2 data present in GOP (1=yes, 0=no) */
/* 5- 3 source resolution (0=720x480/576, 1=704x480/576, 2=352x480/57 */ /* 5- 3 source resolution (0=720x480/576, 1=704x480/576, 2=352x480/57 */
/* 2 source letterboxed (1=yes, 0=no) */ /* 2 source letterboxed (1=yes, 0=no) */
/* 0 film/camera mode (0=camera, 1=film (625/50 only)) */ /* 0 film/camera mode (0=
*camera, 1=film (625/50 only)) */
/* bit definitions for capabilities: */ /* bit definitions for capabilities: */