mirror of
https://github.com/DigitalDevices/dddvb.git
synced 2025-03-01 10:35:23 +00:00
adapt to current mainline kernel dvb-core
This commit is contained in:
@@ -3,6 +3,32 @@
|
||||
# DVB device configuration
|
||||
#
|
||||
|
||||
config DVB_MMAP
|
||||
bool "Enable DVB memory-mapped API (EXPERIMENTAL)"
|
||||
depends on DVB_CORE
|
||||
depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_CORE
|
||||
select VIDEOBUF2_VMALLOC
|
||||
help
|
||||
This option enables DVB experimental memory-mapped API, which
|
||||
reduces the number of context switches to read DVB buffers, as
|
||||
the buffers can use mmap() syscalls.
|
||||
|
||||
Support for it is experimental. Use with care. If unsure,
|
||||
say N.
|
||||
|
||||
config DVB_NET
|
||||
bool "DVB Network Support"
|
||||
default (NET && INET)
|
||||
depends on NET && INET && DVB_CORE
|
||||
help
|
||||
This option enables DVB Network Support which is a part of the DVB
|
||||
standard. It is used, for example, by automatic firmware updates used
|
||||
on Set-Top-Boxes. It can also be used to access the Internet via the
|
||||
DVB card, if the network provider supports it.
|
||||
|
||||
You may want to disable the network support on embedded devices. If
|
||||
unsure say Y.
|
||||
|
||||
config DVB_MAX_ADAPTERS
|
||||
int "maximum number of DVB/ATSC adapters"
|
||||
depends on DVB_CORE
|
||||
@@ -19,7 +45,7 @@ config DVB_MAX_ADAPTERS
|
||||
config DVB_DYNAMIC_MINORS
|
||||
bool "Dynamic DVB minor allocation"
|
||||
depends on DVB_CORE
|
||||
default n
|
||||
default y
|
||||
help
|
||||
If you say Y here, the DVB subsystem will use dynamic minor
|
||||
allocation for any device that uses the DVB major number.
|
||||
@@ -32,7 +58,6 @@ config DVB_DYNAMIC_MINORS
|
||||
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.
|
||||
@@ -41,3 +66,15 @@ config DVB_DEMUX_SECTION_LOSS_LOG
|
||||
be very verbose.
|
||||
|
||||
If you are unsure about this, say N here.
|
||||
|
||||
config DVB_ULE_DEBUG
|
||||
bool "Enable DVB net ULE packet debug messages"
|
||||
depends on DVB_CORE
|
||||
help
|
||||
Enable extra log messages meant to detect problems while
|
||||
handling DVB network ULE 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.
|
||||
|
@@ -3,11 +3,14 @@
|
||||
# Makefile for the kernel DVB device drivers.
|
||||
#
|
||||
|
||||
dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
|
||||
dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
|
||||
dvb-vb2-$(CONFIG_DVB_MMAP) := dvb_vb2.o
|
||||
|
||||
dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o \
|
||||
dvb_ca_en50221.o dvb_frontend.o \
|
||||
dvb_net.o dvb_ringbuffer.o dvb_math.o
|
||||
$(dvb-net-y) dvb_ringbuffer.o $(dvb-vb2-y) dvb_math.o
|
||||
|
||||
obj-$(CONFIG_DVB_CORE) += dvb-core.o
|
||||
|
||||
EXTRA_CFLAGS += -DCONFIG_DVB_DYNAMIC_MINORS -DCONFIG_DVB_NET
|
||||
NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/dvb-core
|
||||
#NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/include/linux
|
||||
|
@@ -9,3 +9,5 @@ dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
|
||||
$(dvb-net-y) dvb_ringbuffer.o dvb_math.o
|
||||
|
||||
obj-$(CONFIG_DVB_CORE) += dvb-core.o
|
||||
|
||||
ccflags-y += -Idrivers/media/dvb-core/
|
||||
|
589
dvb-core/demux.h
589
dvb-core/demux.h
@@ -1,589 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* based on code:
|
||||
* Copyright (c) 2000 Nokia Research Center
|
||||
* Tampere, FINLAND
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DEMUX_H
|
||||
#define __DEMUX_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/dvb/dmx.h>
|
||||
|
||||
/*
|
||||
* Common definitions
|
||||
*/
|
||||
|
||||
/*
|
||||
* DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter.
|
||||
*/
|
||||
|
||||
#ifndef DMX_MAX_FILTER_SIZE
|
||||
#define DMX_MAX_FILTER_SIZE 18
|
||||
#endif
|
||||
|
||||
/*
|
||||
* DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed
|
||||
* filter.
|
||||
*/
|
||||
|
||||
#ifndef DMX_MAX_SECTION_SIZE
|
||||
#define DMX_MAX_SECTION_SIZE 4096
|
||||
#endif
|
||||
#ifndef DMX_MAX_SECFEED_SIZE
|
||||
#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TS packet reception
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum ts_filter_type - filter type bitmap for dmx_ts_feed.set\(\)
|
||||
*
|
||||
* @TS_PACKET: Send TS packets (188 bytes) to callback (default).
|
||||
* @TS_PAYLOAD_ONLY: In case TS_PACKET is set, only send the TS payload
|
||||
* (<=184 bytes per packet) to callback
|
||||
* @TS_DECODER: Send stream to built-in decoder (if present).
|
||||
* @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,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dmx_ts_feed - Structure that contains a TS 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
|
||||
* @set: sets the TS filter
|
||||
* @start_filtering: starts TS filtering
|
||||
* @stop_filtering: stops TS 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_ts_feed {
|
||||
int is_filtering;
|
||||
struct dmx_demux *parent;
|
||||
void *priv;
|
||||
int (*set)(struct dmx_ts_feed *feed,
|
||||
u16 pid,
|
||||
int type,
|
||||
enum dmx_ts_pes pes_type,
|
||||
ktime_t timeout);
|
||||
int (*start_filtering)(struct dmx_ts_feed *feed);
|
||||
int (*stop_filtering)(struct dmx_ts_feed *feed);
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
u8 filter_value[DMX_MAX_FILTER_SIZE];
|
||||
u8 filter_mask[DMX_MAX_FILTER_SIZE];
|
||||
u8 filter_mode[DMX_MAX_FILTER_SIZE];
|
||||
struct dmx_section_feed *parent; /* Back-pointer */
|
||||
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 {
|
||||
int is_filtering;
|
||||
struct dmx_demux *parent;
|
||||
void *priv;
|
||||
|
||||
int check_crc;
|
||||
|
||||
/* private: Used internally at dvb_demux.c */
|
||||
u32 crc_val;
|
||||
|
||||
u8 *secbuf;
|
||||
u8 secbuf_base[DMX_MAX_SECFEED_SIZE];
|
||||
u16 secbufp, seclen, tsfeedp;
|
||||
|
||||
/* public: */
|
||||
int (*set)(struct dmx_section_feed *feed,
|
||||
u16 pid,
|
||||
int check_crc);
|
||||
int (*allocate_filter)(struct dmx_section_feed *feed,
|
||||
struct dmx_section_filter **filter);
|
||||
int (*release_filter)(struct dmx_section_feed *feed,
|
||||
struct dmx_section_filter *filter);
|
||||
int (*start_filtering)(struct dmx_section_feed *feed);
|
||||
int (*stop_filtering)(struct dmx_section_feed *feed);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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,
|
||||
size_t buffer1_length,
|
||||
const u8 *buffer2,
|
||||
size_t buffer2_length,
|
||||
struct dmx_ts_feed *source);
|
||||
|
||||
/**
|
||||
* 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,
|
||||
size_t buffer1_len,
|
||||
const u8 *buffer2,
|
||||
size_t buffer2_len,
|
||||
struct dmx_section_filter *source);
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
DMX_MEMORY_FE,
|
||||
DMX_FRONTEND_0,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 list_head connectivity_list;
|
||||
enum dmx_frontend_source source;
|
||||
};
|
||||
|
||||
/*
|
||||
* MPEG-2 TS Demux
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum dmx_demux_caps - MPEG-2 TS Demux capabilities bitmap
|
||||
*
|
||||
* @DMX_TS_FILTERING: set if TS filtering is supported;
|
||||
* @DMX_SECTION_FILTERING: set if section filtering is supported;
|
||||
* @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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DMX_FE_ENTRY - Casts elements in the list of registered
|
||||
* front-ends from the generic type struct list_head
|
||||
* 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)
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
enum dmx_demux_caps capabilities;
|
||||
struct dmx_frontend *frontend;
|
||||
void *priv;
|
||||
int (*open)(struct dmx_demux *demux);
|
||||
int (*close)(struct dmx_demux *demux);
|
||||
int (*write)(struct dmx_demux *demux, const char __user *buf,
|
||||
size_t count);
|
||||
int (*allocate_ts_feed)(struct dmx_demux *demux,
|
||||
struct dmx_ts_feed **feed,
|
||||
dmx_ts_cb callback);
|
||||
int (*release_ts_feed)(struct dmx_demux *demux,
|
||||
struct dmx_ts_feed *feed);
|
||||
int (*allocate_section_feed)(struct dmx_demux *demux,
|
||||
struct dmx_section_feed **feed,
|
||||
dmx_section_cb callback);
|
||||
int (*release_section_feed)(struct dmx_demux *demux,
|
||||
struct dmx_section_feed *feed);
|
||||
int (*add_frontend)(struct dmx_demux *demux,
|
||||
struct dmx_frontend *frontend);
|
||||
int (*remove_frontend)(struct dmx_demux *demux,
|
||||
struct dmx_frontend *frontend);
|
||||
struct list_head *(*get_frontends)(struct dmx_demux *demux);
|
||||
int (*connect_frontend)(struct dmx_demux *demux,
|
||||
struct dmx_frontend *frontend);
|
||||
int (*disconnect_frontend)(struct dmx_demux *demux);
|
||||
|
||||
int (*get_pes_pids)(struct dmx_demux *demux, u16 *pids);
|
||||
|
||||
/* private: */
|
||||
|
||||
/*
|
||||
* 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,
|
||||
u64 *stc, unsigned int *base);
|
||||
};
|
||||
|
||||
#endif /* #ifndef __DEMUX_H */
|
@@ -18,6 +18,7 @@
|
||||
|
||||
#define pr_fmt(fmt) "dmxdev: " fmt
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -27,8 +28,10 @@
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/version.h>
|
||||
#include "dmxdev.h"
|
||||
#include <media/dmxdev.h>
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
#include <media/dvb_vb2.h>
|
||||
#endif
|
||||
|
||||
static int debug;
|
||||
|
||||
@@ -128,6 +131,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct dmxdev *dmxdev = dvbdev->priv;
|
||||
struct dmx_frontend *front;
|
||||
bool need_ringbuffer = false;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
@@ -139,14 +143,33 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if ((file->f_flags & O_ACCMODE) == O_RDWR) {
|
||||
dmxdev->may_do_mmap = 0;
|
||||
|
||||
/*
|
||||
* The logic here is a little tricky due to the ifdef.
|
||||
*
|
||||
* The ringbuffer is used for both read and mmap.
|
||||
*
|
||||
* It is not needed, however, on two situations:
|
||||
* - Write devices (access with O_WRONLY);
|
||||
* - For duplex device nodes, opened with O_RDWR.
|
||||
*/
|
||||
|
||||
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
|
||||
need_ringbuffer = true;
|
||||
else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
|
||||
if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
dmxdev->may_do_mmap = 1;
|
||||
need_ringbuffer = true;
|
||||
#else
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
|
||||
if (need_ringbuffer) {
|
||||
void *mem;
|
||||
|
||||
if (!dvbdev->readers) {
|
||||
@@ -159,6 +182,11 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
|
||||
return -ENOMEM;
|
||||
}
|
||||
dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
if (dmxdev->may_do_mmap)
|
||||
dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr",
|
||||
file->f_flags & O_NONBLOCK);
|
||||
#endif
|
||||
dvbdev->readers--;
|
||||
}
|
||||
|
||||
@@ -196,7 +224,15 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
|
||||
dmxdev->demux->connect_frontend(dmxdev->demux,
|
||||
dmxdev->dvr_orig_fe);
|
||||
}
|
||||
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
|
||||
if (((file->f_flags & O_ACCMODE) == O_RDONLY) ||
|
||||
dmxdev->may_do_mmap) {
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
if (dmxdev->may_do_mmap) {
|
||||
if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
|
||||
dvb_vb2_stream_off(&dmxdev->dvr_vb2_ctx);
|
||||
dvb_vb2_release(&dmxdev->dvr_vb2_ctx);
|
||||
}
|
||||
#endif
|
||||
dvbdev->readers++;
|
||||
if (dmxdev->dvr_buffer.data) {
|
||||
void *mem = dmxdev->dvr_buffer.data;
|
||||
@@ -381,12 +417,18 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
|
||||
#endif
|
||||
static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
|
||||
const u8 *buffer2, size_t buffer2_len,
|
||||
struct dmx_section_filter *filter)
|
||||
struct dmx_section_filter *filter,
|
||||
u32 *buffer_flags)
|
||||
{
|
||||
struct dmxdev_filter *dmxdevfilter = filter->priv;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
if (!dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx) &&
|
||||
dmxdevfilter->buffer.error) {
|
||||
#else
|
||||
if (dmxdevfilter->buffer.error) {
|
||||
#endif
|
||||
wake_up(&dmxdevfilter->buffer.queue);
|
||||
return 0;
|
||||
}
|
||||
@@ -397,12 +439,31 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
|
||||
}
|
||||
del_timer(&dmxdevfilter->timer);
|
||||
dprintk("section callback %*ph\n", 6, buffer1);
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) {
|
||||
ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
|
||||
buffer1, buffer1_len,
|
||||
buffer_flags);
|
||||
if (ret == buffer1_len)
|
||||
ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
|
||||
buffer2, buffer2_len,
|
||||
buffer_flags);
|
||||
} else {
|
||||
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer,
|
||||
buffer1, buffer1_len);
|
||||
if (ret == buffer1_len) {
|
||||
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer,
|
||||
buffer2, buffer2_len);
|
||||
}
|
||||
}
|
||||
#else
|
||||
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
|
||||
buffer1_len);
|
||||
if (ret == buffer1_len) {
|
||||
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
|
||||
buffer2_len);
|
||||
}
|
||||
#endif
|
||||
if (ret < 0)
|
||||
dmxdevfilter->buffer.error = ret;
|
||||
if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
|
||||
@@ -414,7 +475,8 @@ 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,
|
||||
const u8 *buffer2, size_t buffer2_len,
|
||||
struct dmx_ts_feed *feed)
|
||||
struct dmx_ts_feed *feed,
|
||||
u32 *buffer_flags)
|
||||
{
|
||||
struct dmxdev_filter *dmxdevfilter = feed->priv;
|
||||
struct dvb_ringbuffer *buffer;
|
||||
@@ -426,19 +488,40 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
|
||||
|| dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
|
||||
if (dmxdevfilter->params.pes.output == DMX_OUT_TAP ||
|
||||
dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) {
|
||||
buffer = &dmxdevfilter->buffer;
|
||||
else
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
ctx = &dmxdevfilter->vb2_ctx;
|
||||
#endif
|
||||
} else {
|
||||
buffer = &dmxdevfilter->dev->dvr_buffer;
|
||||
if (buffer->error) {
|
||||
spin_unlock(&dmxdevfilter->dev->lock);
|
||||
wake_up(&buffer->queue);
|
||||
return 0;
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
ctx = &dmxdevfilter->dev->dvr_vb2_ctx;
|
||||
#endif
|
||||
}
|
||||
ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
|
||||
if (ret == buffer1_len)
|
||||
ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
|
||||
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
if (dvb_vb2_is_streaming(ctx)) {
|
||||
ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len,
|
||||
buffer_flags);
|
||||
if (ret == buffer1_len)
|
||||
ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len,
|
||||
buffer_flags);
|
||||
} else {
|
||||
#endif
|
||||
if (buffer->error) {
|
||||
spin_unlock(&dmxdevfilter->dev->lock);
|
||||
wake_up(&buffer->queue);
|
||||
return 0;
|
||||
}
|
||||
ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
|
||||
if (ret == buffer1_len)
|
||||
ret = dvb_dmxdev_buffer_write(buffer,
|
||||
buffer2, buffer2_len);
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
}
|
||||
#endif
|
||||
if (ret < 0)
|
||||
buffer->error = ret;
|
||||
spin_unlock(&dmxdevfilter->dev->lock);
|
||||
@@ -585,7 +668,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
|
||||
struct dmxdev_filter *filter,
|
||||
struct dmxdev_feed *feed)
|
||||
{
|
||||
ktime_t timeout;
|
||||
ktime_t timeout = ktime_set(0, 0);
|
||||
struct dmx_pes_filter_params *para = &filter->params.pes;
|
||||
enum dmx_output otype;
|
||||
int ret;
|
||||
@@ -593,7 +676,6 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
|
||||
enum dmx_ts_pes ts_pes;
|
||||
struct dmx_ts_feed *tsfeed;
|
||||
|
||||
timeout = ktime_set(0, 0);
|
||||
feed->ts = NULL;
|
||||
otype = para->output;
|
||||
|
||||
@@ -777,7 +859,17 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
|
||||
mutex_init(&dmxdevfilter->mutex);
|
||||
file->private_data = dmxdevfilter;
|
||||
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
dmxdev->may_do_mmap = 1;
|
||||
#else
|
||||
dmxdev->may_do_mmap = 0;
|
||||
#endif
|
||||
|
||||
dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
dvb_vb2_init(&dmxdevfilter->vb2_ctx, "demux_filter",
|
||||
file->f_flags & O_NONBLOCK);
|
||||
#endif
|
||||
dmxdevfilter->type = DMXDEV_TYPE_NONE;
|
||||
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
|
||||
@@ -797,6 +889,11 @@ static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
|
||||
{
|
||||
mutex_lock(&dmxdev->mutex);
|
||||
mutex_lock(&dmxdevfilter->mutex);
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx))
|
||||
dvb_vb2_stream_off(&dmxdevfilter->vb2_ctx);
|
||||
dvb_vb2_release(&dmxdevfilter->vb2_ctx);
|
||||
#endif
|
||||
|
||||
dvb_dmxdev_filter_stop(dmxdevfilter);
|
||||
dvb_dmxdev_filter_reset(dmxdevfilter);
|
||||
@@ -1084,8 +1181,56 @@ static int dvb_demux_do_ioctl(struct file *file,
|
||||
mutex_unlock(&dmxdevfilter->mutex);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
case DMX_REQBUFS:
|
||||
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
ret = dvb_vb2_reqbufs(&dmxdevfilter->vb2_ctx, parg);
|
||||
mutex_unlock(&dmxdevfilter->mutex);
|
||||
break;
|
||||
|
||||
case DMX_QUERYBUF:
|
||||
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
ret = dvb_vb2_querybuf(&dmxdevfilter->vb2_ctx, parg);
|
||||
mutex_unlock(&dmxdevfilter->mutex);
|
||||
break;
|
||||
|
||||
case DMX_EXPBUF:
|
||||
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
ret = dvb_vb2_expbuf(&dmxdevfilter->vb2_ctx, parg);
|
||||
mutex_unlock(&dmxdevfilter->mutex);
|
||||
break;
|
||||
|
||||
case DMX_QBUF:
|
||||
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
ret = dvb_vb2_qbuf(&dmxdevfilter->vb2_ctx, parg);
|
||||
if (ret == 0 && !dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx))
|
||||
ret = dvb_vb2_stream_on(&dmxdevfilter->vb2_ctx);
|
||||
mutex_unlock(&dmxdevfilter->mutex);
|
||||
break;
|
||||
|
||||
case DMX_DQBUF:
|
||||
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
ret = dvb_vb2_dqbuf(&dmxdevfilter->vb2_ctx, parg);
|
||||
mutex_unlock(&dmxdevfilter->mutex);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
ret = -ENOTTY;
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
@@ -1098,30 +1243,70 @@ static long dvb_demux_ioctl(struct file *file, unsigned int cmd,
|
||||
return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);
|
||||
}
|
||||
|
||||
static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0))
|
||||
typedef unsigned int __poll_t;
|
||||
#define EPOLLIN POLLIN
|
||||
#define EPOLLERR POLLERR
|
||||
#define EPOLLPRI POLLPRI
|
||||
#define EPOLLRDNORM POLLRDNORM
|
||||
#define EPOLLWRNORM POLLWRNORM
|
||||
#define EPOLLOUT POLLOUT
|
||||
#endif
|
||||
|
||||
static __poll_t dvb_demux_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct dmxdev_filter *dmxdevfilter = file->private_data;
|
||||
unsigned int mask = 0;
|
||||
|
||||
if ((!dmxdevfilter) || dmxdevfilter->dev->exit)
|
||||
return POLLERR;
|
||||
__poll_t mask = 0;
|
||||
|
||||
poll_wait(file, &dmxdevfilter->buffer.queue, wait);
|
||||
|
||||
if ((!dmxdevfilter) || dmxdevfilter->dev->exit)
|
||||
return EPOLLERR;
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx))
|
||||
return dvb_vb2_poll(&dmxdevfilter->vb2_ctx, file, wait);
|
||||
#endif
|
||||
|
||||
if (dmxdevfilter->state != DMXDEV_STATE_GO &&
|
||||
dmxdevfilter->state != DMXDEV_STATE_DONE &&
|
||||
dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT)
|
||||
return 0;
|
||||
|
||||
if (dmxdevfilter->buffer.error)
|
||||
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
|
||||
mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR);
|
||||
|
||||
if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
|
||||
mask |= (POLLIN | POLLRDNORM | POLLPRI);
|
||||
mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
static int dvb_demux_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
struct dmxdev_filter *dmxdevfilter = file->private_data;
|
||||
struct dmxdev *dmxdev = dmxdevfilter->dev;
|
||||
int ret;
|
||||
|
||||
if (!dmxdev->may_do_mmap)
|
||||
return -ENOTTY;
|
||||
|
||||
if (mutex_lock_interruptible(&dmxdev->mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
ret = dvb_vb2_mmap(&dmxdevfilter->vb2_ctx, vma);
|
||||
|
||||
mutex_unlock(&dmxdevfilter->mutex);
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dvb_demux_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dmxdev_filter *dmxdevfilter = file->private_data;
|
||||
@@ -1146,10 +1331,14 @@ static const struct file_operations dvb_demux_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = dvb_demux_read,
|
||||
.unlocked_ioctl = dvb_demux_ioctl,
|
||||
.compat_ioctl = dvb_demux_ioctl,
|
||||
.open = dvb_demux_open,
|
||||
.release = dvb_demux_release,
|
||||
.poll = dvb_demux_poll,
|
||||
.llseek = default_llseek,
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
.mmap = dvb_demux_mmap,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct dvb_device dvbdev_demux = {
|
||||
@@ -1178,8 +1367,31 @@ static int dvb_dvr_do_ioctl(struct file *file,
|
||||
ret = dvb_dvr_set_buffer_size(dmxdev, arg);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
case DMX_REQBUFS:
|
||||
ret = dvb_vb2_reqbufs(&dmxdev->dvr_vb2_ctx, parg);
|
||||
break;
|
||||
|
||||
case DMX_QUERYBUF:
|
||||
ret = dvb_vb2_querybuf(&dmxdev->dvr_vb2_ctx, parg);
|
||||
break;
|
||||
|
||||
case DMX_EXPBUF:
|
||||
ret = dvb_vb2_expbuf(&dmxdev->dvr_vb2_ctx, parg);
|
||||
break;
|
||||
|
||||
case DMX_QBUF:
|
||||
ret = dvb_vb2_qbuf(&dmxdev->dvr_vb2_ctx, parg);
|
||||
if (ret == 0 && !dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
|
||||
ret = dvb_vb2_stream_on(&dmxdev->dvr_vb2_ctx);
|
||||
break;
|
||||
|
||||
case DMX_DQBUF:
|
||||
ret = dvb_vb2_dqbuf(&dmxdev->dvr_vb2_ctx, parg);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
ret = -ENOTTY;
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
@@ -1192,31 +1404,58 @@ static long dvb_dvr_ioctl(struct file *file,
|
||||
return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);
|
||||
}
|
||||
|
||||
static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
|
||||
static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct dmxdev *dmxdev = dvbdev->priv;
|
||||
unsigned int mask = 0;
|
||||
__poll_t mask = 0;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
if (dmxdev->exit)
|
||||
return POLLERR;
|
||||
|
||||
poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
|
||||
|
||||
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
|
||||
if (dmxdev->exit)
|
||||
return EPOLLERR;
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
|
||||
return dvb_vb2_poll(&dmxdev->dvr_vb2_ctx, file, wait);
|
||||
#endif
|
||||
|
||||
if (((file->f_flags & O_ACCMODE) == O_RDONLY) ||
|
||||
dmxdev->may_do_mmap) {
|
||||
if (dmxdev->dvr_buffer.error)
|
||||
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
|
||||
mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR);
|
||||
|
||||
if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
|
||||
mask |= (POLLIN | POLLRDNORM | POLLPRI);
|
||||
mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI);
|
||||
} else
|
||||
mask |= (POLLOUT | POLLWRNORM | POLLPRI);
|
||||
mask |= (EPOLLOUT | EPOLLWRNORM | EPOLLPRI);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
static int dvb_dvr_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct dmxdev *dmxdev = dvbdev->priv;
|
||||
int ret;
|
||||
|
||||
if (!dmxdev->may_do_mmap)
|
||||
return -ENOTTY;
|
||||
|
||||
if (dmxdev->exit)
|
||||
return -ENODEV;
|
||||
|
||||
if (mutex_lock_interruptible(&dmxdev->mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
ret = dvb_vb2_mmap(&dmxdev->dvr_vb2_ctx, vma);
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct file_operations dvb_dvr_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = dvb_dvr_read,
|
||||
@@ -1226,6 +1465,9 @@ static const struct file_operations dvb_dvr_fops = {
|
||||
.release = dvb_dvr_release,
|
||||
.poll = dvb_dvr_poll,
|
||||
.llseek = default_llseek,
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
.mmap = dvb_dvr_mmap,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct dvb_device dvbdev_dvr = {
|
||||
@@ -1237,6 +1479,7 @@ static const struct dvb_device dvbdev_dvr = {
|
||||
#endif
|
||||
.fops = &dvb_dvr_fops
|
||||
};
|
||||
|
||||
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
|
||||
{
|
||||
int i;
|
||||
@@ -1244,7 +1487,12 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
|
||||
if (dmxdev->demux->open(dmxdev->demux) < 0)
|
||||
return -EUSERS;
|
||||
|
||||
dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter));
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0))
|
||||
dmxdev->filter = vmalloc(sizeof(struct dmxdev_filter) * dmxdev->filternum);
|
||||
#else
|
||||
dmxdev->filter = vmalloc(array_size(sizeof(struct dmxdev_filter),
|
||||
dmxdev->filternum));
|
||||
#endif
|
||||
if (!dmxdev->filter)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* dmxdev.h
|
||||
*
|
||||
* Copyright (C) 2000 Ralph Metzler & Marcus Metzler
|
||||
* for convergence integrated media GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DMXDEV_H_
|
||||
#define _DMXDEV_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/dvb/dmx.h>
|
||||
|
||||
#include "dvbdev.h"
|
||||
#include "demux.h"
|
||||
#include "dvb_ringbuffer.h"
|
||||
|
||||
enum dmxdev_type {
|
||||
DMXDEV_TYPE_NONE,
|
||||
DMXDEV_TYPE_SEC,
|
||||
DMXDEV_TYPE_PES,
|
||||
};
|
||||
|
||||
enum dmxdev_state {
|
||||
DMXDEV_STATE_FREE,
|
||||
DMXDEV_STATE_ALLOCATED,
|
||||
DMXDEV_STATE_SET,
|
||||
DMXDEV_STATE_GO,
|
||||
DMXDEV_STATE_DONE,
|
||||
DMXDEV_STATE_TIMEDOUT
|
||||
};
|
||||
|
||||
struct dmxdev_feed {
|
||||
u16 pid;
|
||||
struct dmx_ts_feed *ts;
|
||||
struct list_head next;
|
||||
};
|
||||
|
||||
struct dmxdev_filter {
|
||||
union {
|
||||
struct dmx_section_filter *sec;
|
||||
} filter;
|
||||
|
||||
union {
|
||||
/* list of TS and PES feeds (struct dmxdev_feed) */
|
||||
struct list_head ts;
|
||||
struct dmx_section_feed *sec;
|
||||
} feed;
|
||||
|
||||
union {
|
||||
struct dmx_sct_filter_params sec;
|
||||
struct dmx_pes_filter_params pes;
|
||||
} params;
|
||||
|
||||
enum dmxdev_type type;
|
||||
enum dmxdev_state state;
|
||||
struct dmxdev *dev;
|
||||
struct dvb_ringbuffer buffer;
|
||||
|
||||
struct mutex mutex;
|
||||
|
||||
/* only for sections */
|
||||
struct timer_list timer;
|
||||
int todo;
|
||||
u8 secheader[3];
|
||||
};
|
||||
|
||||
|
||||
struct dmxdev {
|
||||
struct dvb_device *dvbdev;
|
||||
struct dvb_device *dvr_dvbdev;
|
||||
|
||||
struct dmxdev_filter *filter;
|
||||
struct dmx_demux *demux;
|
||||
|
||||
int filternum;
|
||||
int capabilities;
|
||||
|
||||
unsigned int exit:1;
|
||||
#define DMXDEV_CAP_DUPLEX 1
|
||||
struct dmx_frontend *dvr_orig_fe;
|
||||
|
||||
struct dvb_ringbuffer dvr_buffer;
|
||||
#define DVR_BUFFER_SIZE (10*188*1024)
|
||||
|
||||
struct mutex mutex;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
|
||||
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *);
|
||||
void dvb_dmxdev_release(struct dmxdev *dmxdev);
|
||||
|
||||
#endif /* _DMXDEV_H_ */
|
@@ -34,8 +34,8 @@
|
||||
#endif
|
||||
#include <linux/kthread.h>
|
||||
|
||||
#include "dvb_ca_en50221.h"
|
||||
#include "dvb_ringbuffer.h"
|
||||
#include <media/dvb_ca_en50221.h>
|
||||
#include <media/dvb_ringbuffer.h>
|
||||
|
||||
static int dvb_ca_en50221_debug;
|
||||
|
||||
|
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* dvb_ca.h: generic DVB functions for EN50221 CA interfaces
|
||||
*
|
||||
* Copyright (C) 2004 Andrew de Quincey
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _DVB_CA_EN50221_H_
|
||||
#define _DVB_CA_EN50221_H_
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/dvb/ca.h>
|
||||
|
||||
#include "dvbdev.h"
|
||||
|
||||
#define DVB_CA_EN50221_POLL_CAM_PRESENT 1
|
||||
#define DVB_CA_EN50221_POLL_CAM_CHANGED 2
|
||||
#define DVB_CA_EN50221_POLL_CAM_READY 4
|
||||
|
||||
#define DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE 1
|
||||
#define DVB_CA_EN50221_FLAG_IRQ_FR 2
|
||||
#define DVB_CA_EN50221_FLAG_IRQ_DA 4
|
||||
|
||||
#define DVB_CA_EN50221_CAMCHANGE_REMOVED 0
|
||||
#define DVB_CA_EN50221_CAMCHANGE_INSERTED 1
|
||||
|
||||
/**
|
||||
* struct dvb_ca_en50221- Structure describing a CA interface
|
||||
*
|
||||
* @owner: the module owning this structure
|
||||
* @read_attribute_mem: function for reading attribute memory on the CAM
|
||||
* @write_attribute_mem: function for writing attribute memory on the CAM
|
||||
* @read_cam_control: function for reading the control interface on the CAM
|
||||
* @write_cam_control: function for reading the control interface on the CAM
|
||||
* @read_data: function for reading data (block mode)
|
||||
* @write_data: function for writing data (block mode)
|
||||
* @slot_reset: function to reset the CAM slot
|
||||
* @slot_shutdown: function to shutdown a CAM slot
|
||||
* @slot_ts_enable: function to enable the Transport Stream on a CAM slot
|
||||
* @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
|
||||
* and if appropriate. There will be no concurrent access to one slot.
|
||||
*/
|
||||
struct dvb_ca_en50221 {
|
||||
struct module *owner;
|
||||
|
||||
int (*read_attribute_mem)(struct dvb_ca_en50221 *ca,
|
||||
int slot, int address);
|
||||
int (*write_attribute_mem)(struct dvb_ca_en50221 *ca,
|
||||
int slot, int address, u8 value);
|
||||
|
||||
int (*read_cam_control)(struct dvb_ca_en50221 *ca,
|
||||
int slot, u8 address);
|
||||
int (*write_cam_control)(struct dvb_ca_en50221 *ca,
|
||||
int slot, u8 address, u8 value);
|
||||
|
||||
int (*read_data)(struct dvb_ca_en50221 *ca,
|
||||
int slot, u8 *ebuf, int ecount);
|
||||
int (*write_data)(struct dvb_ca_en50221 *ca,
|
||||
int slot, u8 *ebuf, int ecount);
|
||||
|
||||
int (*slot_reset)(struct dvb_ca_en50221 *ca, int slot);
|
||||
int (*slot_shutdown)(struct dvb_ca_en50221 *ca, int slot);
|
||||
int (*slot_ts_enable)(struct dvb_ca_en50221 *ca, int slot);
|
||||
|
||||
int (*poll_slot_status)(struct dvb_ca_en50221 *ca, int slot, int open);
|
||||
|
||||
void *data;
|
||||
|
||||
void *private;
|
||||
};
|
||||
|
||||
/*
|
||||
* Functions for reporting IRQ events
|
||||
*/
|
||||
|
||||
/**
|
||||
* dvb_ca_en50221_camchange_irq - A CAMCHANGE IRQ has occurred.
|
||||
*
|
||||
* @pubca: CA instance.
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* dvb_ca_en50221_frda_irq - An FR or a DA IRQ has occurred.
|
||||
*
|
||||
* @ca: CA instance.
|
||||
* @slot: Slot concerned.
|
||||
*/
|
||||
void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *ca, int slot);
|
||||
|
||||
/*
|
||||
* Initialisation/shutdown functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* dvb_ca_en50221_init - Initialise a new DVB CA device.
|
||||
*
|
||||
* @dvb_adapter: DVB adapter to attach the new CA device to.
|
||||
* @ca: The dvb_ca instance.
|
||||
* @flags: Flags describing the CA device (DVB_CA_EN50221_FLAG_*).
|
||||
* @slot_count: Number of slots supported.
|
||||
*
|
||||
* @return 0 on success, nonzero on failure
|
||||
*/
|
||||
int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
|
||||
struct dvb_ca_en50221 *ca, int flags,
|
||||
int slot_count);
|
||||
|
||||
/**
|
||||
* dvb_ca_en50221_release - Release a DVB CA device.
|
||||
*
|
||||
* @ca: The associated dvb_ca instance.
|
||||
*/
|
||||
void dvb_ca_en50221_release(struct dvb_ca_en50221 *ca);
|
||||
|
||||
#endif
|
@@ -35,7 +35,7 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "dvb_demux.h"
|
||||
#include <media/dvb_demux.h>
|
||||
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
|
||||
@@ -68,6 +68,17 @@ MODULE_PARM_DESC(dvb_demux_feed_err_pkts,
|
||||
dprintk(x); \
|
||||
} while (0)
|
||||
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
# define dprintk_sect_loss(x...) dprintk(x)
|
||||
#else
|
||||
# define dprintk_sect_loss(x...)
|
||||
#endif
|
||||
|
||||
#define set_buf_flags(__feed, __flag) \
|
||||
do { \
|
||||
(__feed)->buffer_flags |= (__flag); \
|
||||
} while (0)
|
||||
|
||||
/******************************************************************************
|
||||
* static inlined helper functions
|
||||
******************************************************************************/
|
||||
@@ -117,30 +128,30 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
|
||||
{
|
||||
int count = payload(buf);
|
||||
int p;
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
int ccok;
|
||||
u8 cc;
|
||||
#endif
|
||||
|
||||
if (count == 0)
|
||||
return -1;
|
||||
|
||||
p = 188 - count;
|
||||
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
cc = buf[3] & 0x0f;
|
||||
ccok = ((feed->cc + 1) & 0x0f) == cc;
|
||||
feed->cc = cc;
|
||||
if (!ccok)
|
||||
dprintk("missed packet!\n");
|
||||
#endif
|
||||
if (!ccok) {
|
||||
set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
|
||||
dprintk_sect_loss("missed packet: %d instead of %d!\n",
|
||||
cc, (feed->cc + 1) & 0x0f);
|
||||
}
|
||||
|
||||
if (buf[1] & 0x40) // PUSI ?
|
||||
feed->peslen = 0xfffa;
|
||||
|
||||
feed->peslen += count;
|
||||
|
||||
return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts);
|
||||
return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts,
|
||||
&feed->buffer_flags);
|
||||
}
|
||||
|
||||
static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
|
||||
@@ -162,7 +173,7 @@ static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
|
||||
return 0;
|
||||
|
||||
return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen,
|
||||
NULL, 0, &f->filter);
|
||||
NULL, 0, &f->filter, &feed->buffer_flags);
|
||||
}
|
||||
|
||||
static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
|
||||
@@ -181,8 +192,10 @@ static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
|
||||
if (sec->check_crc) {
|
||||
section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
|
||||
if (section_syntax_indicator &&
|
||||
demux->check_crc32(feed, sec->secbuf, sec->seclen))
|
||||
demux->check_crc32(feed, sec->secbuf, sec->seclen)) {
|
||||
set_buf_flags(feed, DMX_BUFFER_FLAG_HAD_CRC32_DISCARD);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -199,9 +212,8 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
|
||||
{
|
||||
struct dmx_section_feed *sec = &feed->feed.sec;
|
||||
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
if (sec->secbufp < sec->tsfeedp) {
|
||||
int i, n = sec->tsfeedp - sec->secbufp;
|
||||
int n = sec->tsfeedp - sec->secbufp;
|
||||
|
||||
/*
|
||||
* Section padding is done with 0xff bytes entirely.
|
||||
@@ -209,15 +221,13 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
|
||||
* but just first and last.
|
||||
*/
|
||||
if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) {
|
||||
dprintk("dvb_demux.c section ts padding loss: %d/%d\n",
|
||||
n, sec->tsfeedp);
|
||||
dprintk("dvb_demux.c pad data:");
|
||||
for (i = 0; i < n; i++)
|
||||
pr_cont(" %02x", sec->secbuf[i]);
|
||||
pr_cont("\n");
|
||||
set_buf_flags(feed,
|
||||
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
|
||||
dprintk_sect_loss("section ts padding loss: %d/%d\n",
|
||||
n, sec->tsfeedp);
|
||||
dprintk_sect_loss("pad data: %*ph\n", n, sec->secbuf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
sec->tsfeedp = sec->secbufp = sec->seclen = 0;
|
||||
sec->secbuf = sec->secbuf_base;
|
||||
@@ -236,10 +246,10 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
|
||||
* when the second packet arrives.
|
||||
*
|
||||
* Fix:
|
||||
* when demux is started, let feed->pusi_seen = 0 to
|
||||
* when demux is started, let feed->pusi_seen = false to
|
||||
* prevent initial feeding of garbage from the end of
|
||||
* previous section. When you for the first time see PUSI=1
|
||||
* then set feed->pusi_seen = 1
|
||||
* then set feed->pusi_seen = true
|
||||
*/
|
||||
static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
|
||||
const u8 *buf, u8 len)
|
||||
@@ -252,11 +262,10 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
|
||||
return 0;
|
||||
|
||||
if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
dprintk("dvb_demux.c section buffer full loss: %d/%d\n",
|
||||
sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
|
||||
DMX_MAX_SECFEED_SIZE);
|
||||
#endif
|
||||
set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
|
||||
dprintk_sect_loss("section buffer full loss: %d/%d\n",
|
||||
sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
|
||||
DMX_MAX_SECFEED_SIZE);
|
||||
len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp;
|
||||
}
|
||||
|
||||
@@ -284,12 +293,13 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
|
||||
sec->seclen = seclen;
|
||||
sec->crc_val = ~0;
|
||||
/* dump [secbuf .. secbuf+seclen) */
|
||||
if (feed->pusi_seen)
|
||||
if (feed->pusi_seen) {
|
||||
dvb_dmx_swfilter_section_feed(feed);
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
else
|
||||
dprintk("dvb_demux.c pusi not seen, discarding section data\n");
|
||||
#endif
|
||||
} else {
|
||||
set_buf_flags(feed,
|
||||
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
|
||||
dprintk_sect_loss("pusi not seen, discarding section data\n");
|
||||
}
|
||||
sec->secbufp += seclen; /* secbufp and secbuf moving together is */
|
||||
sec->secbuf += seclen; /* redundant but saves pointer arithmetic */
|
||||
}
|
||||
@@ -322,19 +332,31 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
|
||||
}
|
||||
|
||||
if (!ccok || dc_i) {
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
dprintk("dvb_demux.c discontinuity detected %d bytes lost\n",
|
||||
count);
|
||||
if (dc_i) {
|
||||
set_buf_flags(feed,
|
||||
DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR);
|
||||
dprintk_sect_loss("%d frame with disconnect indicator\n",
|
||||
cc);
|
||||
} else {
|
||||
set_buf_flags(feed,
|
||||
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
|
||||
dprintk_sect_loss("discontinuity: %d instead of %d. %d bytes lost\n",
|
||||
cc, (feed->cc + 1) & 0x0f, count + 4);
|
||||
}
|
||||
/*
|
||||
* those bytes under sume circumstances will again be reported
|
||||
* those bytes under some circumstances will again be reported
|
||||
* in the following dvb_dmx_swfilter_section_new
|
||||
*/
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Discontinuity detected. Reset pusi_seen = 0 to
|
||||
* Discontinuity detected. Reset pusi_seen to
|
||||
* stop feeding of suspicious data until next PUSI=1 arrives
|
||||
*
|
||||
* FIXME: does it make sense if the MPEG-TS is the one
|
||||
* reporting discontinuity?
|
||||
*/
|
||||
feed->pusi_seen = 0;
|
||||
|
||||
feed->pusi_seen = false;
|
||||
dvb_dmx_swfilter_section_new(feed);
|
||||
}
|
||||
|
||||
@@ -348,17 +370,16 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
|
||||
|
||||
dvb_dmx_swfilter_section_copy_dump(feed, before,
|
||||
before_len);
|
||||
/* before start of new section, set pusi_seen = 1 */
|
||||
feed->pusi_seen = 1;
|
||||
/* before start of new section, set pusi_seen */
|
||||
feed->pusi_seen = true;
|
||||
dvb_dmx_swfilter_section_new(feed);
|
||||
dvb_dmx_swfilter_section_copy_dump(feed, after,
|
||||
after_len);
|
||||
} else if (count > 0) {
|
||||
set_buf_flags(feed,
|
||||
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
|
||||
dprintk_sect_loss("PUSI=1 but %d bytes lost\n", count);
|
||||
}
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
else if (count > 0)
|
||||
dprintk("dvb_demux.c PUSI=1 but %d bytes lost\n",
|
||||
count);
|
||||
#endif
|
||||
} else {
|
||||
/* PUSI=0 (is not set), no section boundary */
|
||||
dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count);
|
||||
@@ -378,8 +399,10 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
|
||||
if (feed->ts_type & TS_PAYLOAD_ONLY)
|
||||
dvb_dmx_swfilter_payload(feed, buf);
|
||||
else
|
||||
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts);
|
||||
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
|
||||
&feed->buffer_flags);
|
||||
}
|
||||
/* Used only on full-featured devices */
|
||||
if (feed->ts_type & TS_DECODER)
|
||||
if (feed->demux->write_to_decoder)
|
||||
feed->demux->write_to_decoder(feed, buf, 188);
|
||||
@@ -426,9 +449,10 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
|
||||
1024);
|
||||
speed_timedelta = ktime_ms_delta(cur_time,
|
||||
demux->speed_last_time);
|
||||
dprintk("TS speed %llu Kbits/sec \n",
|
||||
div64_u64(speed_bytes,
|
||||
speed_timedelta));
|
||||
if (speed_timedelta)
|
||||
dprintk("TS speed %llu Kbits/sec \n",
|
||||
div64_u64(speed_bytes,
|
||||
speed_timedelta));
|
||||
}
|
||||
|
||||
demux->speed_last_time = cur_time;
|
||||
@@ -437,6 +461,11 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
|
||||
}
|
||||
|
||||
if (buf[1] & 0x80) {
|
||||
list_for_each_entry(feed, &demux->feed_list, list_head) {
|
||||
if ((feed->pid != pid) && (feed->pid != 0x2000))
|
||||
continue;
|
||||
set_buf_flags(feed, DMX_BUFFER_FLAG_TEI);
|
||||
}
|
||||
dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n",
|
||||
pid, buf[1]);
|
||||
/* data in this packet can't be trusted - drop it unless
|
||||
@@ -452,6 +481,13 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
|
||||
(demux->cnt_storage[pid] + 1) & 0xf;
|
||||
|
||||
if ((buf[3] & 0xf) != demux->cnt_storage[pid]) {
|
||||
list_for_each_entry(feed, &demux->feed_list, list_head) {
|
||||
if ((feed->pid != pid) && (feed->pid != 0x2000))
|
||||
continue;
|
||||
set_buf_flags(feed,
|
||||
DMX_BUFFER_PKT_COUNTER_MISMATCH);
|
||||
}
|
||||
|
||||
dprintk_tscheck("TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n",
|
||||
pid, demux->cnt_storage[pid],
|
||||
buf[3] & 0xf);
|
||||
@@ -473,7 +509,8 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
|
||||
if (feed->pid == pid)
|
||||
dvb_dmx_swfilter_packet_type(feed, buf);
|
||||
else if (feed->pid == 0x2000)
|
||||
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts);
|
||||
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
|
||||
&feed->buffer_flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,7 +629,16 @@ void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
|
||||
|
||||
spin_lock_irqsave(&demux->lock, flags);
|
||||
|
||||
demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts);
|
||||
#if 1
|
||||
demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts,
|
||||
&demux->feed->buffer_flags);
|
||||
#else
|
||||
struct dvb_demux_feed *feed;
|
||||
list_for_each_entry(feed, &demux->feed_list, list_head) {
|
||||
feed->cb.ts(buf, count, NULL, 0, &feed->feed.ts,
|
||||
&feed->buffer_flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
spin_unlock_irqrestore(&demux->lock, flags);
|
||||
}
|
||||
@@ -792,6 +838,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
|
||||
feed->demux = demux;
|
||||
feed->pid = 0xffff;
|
||||
feed->peslen = 0xfffa;
|
||||
feed->buffer_flags = 0;
|
||||
|
||||
(*ts_feed) = &feed->feed.ts;
|
||||
(*ts_feed)->parent = dmx;
|
||||
@@ -911,14 +958,14 @@ static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
|
||||
return;
|
||||
do {
|
||||
sf = &f->filter;
|
||||
doneq = 0;
|
||||
doneq = false;
|
||||
for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
|
||||
mode = sf->filter_mode[i];
|
||||
mask = sf->filter_mask[i];
|
||||
f->maskandmode[i] = mask & mode;
|
||||
doneq |= f->maskandnotmode[i] = mask & ~mode;
|
||||
}
|
||||
f->doneq = doneq ? 1 : 0;
|
||||
f->doneq = doneq ? true : false;
|
||||
} while ((f = f->next));
|
||||
}
|
||||
|
||||
@@ -945,6 +992,7 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
|
||||
dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
|
||||
dvbdmxfeed->feed.sec.secbufp = 0;
|
||||
dvbdmxfeed->feed.sec.seclen = 0;
|
||||
dvbdmxfeed->pusi_seen = false;
|
||||
|
||||
if (!dvbdmx->start_feed) {
|
||||
mutex_unlock(&dvbdmx->mutex);
|
||||
@@ -1049,6 +1097,7 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
|
||||
dvbdmxfeed->cb.sec = callback;
|
||||
dvbdmxfeed->demux = dvbdmx;
|
||||
dvbdmxfeed->pid = 0xffff;
|
||||
dvbdmxfeed->buffer_flags = 0;
|
||||
dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
|
||||
dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
|
||||
dvbdmxfeed->feed.sec.tsfeedp = 0;
|
||||
@@ -1220,12 +1269,25 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
|
||||
|
||||
dvbdemux->cnt_storage = NULL;
|
||||
dvbdemux->users = 0;
|
||||
dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter));
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0))
|
||||
dvbdemux->filter = vmalloc(sizeof(struct dvb_demux_filter) *
|
||||
dvbdemux->filternum);
|
||||
|
||||
if (!dvbdemux->filter)
|
||||
return -ENOMEM;
|
||||
|
||||
dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed));
|
||||
dvbdemux->feed = vmalloc(sizeof(struct dvb_demux_feed) *
|
||||
dvbdemux->feednum);
|
||||
#else
|
||||
dvbdemux->filter = vmalloc(array_size(sizeof(struct dvb_demux_filter),
|
||||
dvbdemux->filternum));
|
||||
|
||||
if (!dvbdemux->filter)
|
||||
return -ENOMEM;
|
||||
|
||||
dvbdemux->feed = vmalloc(array_size(sizeof(struct dvb_demux_feed),
|
||||
dvbdemux->feednum));
|
||||
#endif
|
||||
if (!dvbdemux->feed) {
|
||||
vfree(dvbdemux->filter);
|
||||
dvbdemux->filter = NULL;
|
||||
|
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* dvb_demux.h: DVB kernel demux API
|
||||
*
|
||||
* Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
|
||||
* for convergence integrated media GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DVB_DEMUX_H_
|
||||
#define _DVB_DEMUX_H_
|
||||
|
||||
#include <linux/time.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "demux.h"
|
||||
|
||||
#define DMX_TYPE_TS 0
|
||||
#define DMX_TYPE_SEC 1
|
||||
#define DMX_TYPE_PES 2
|
||||
|
||||
#define DMX_STATE_FREE 0
|
||||
#define DMX_STATE_ALLOCATED 1
|
||||
#define DMX_STATE_SET 2
|
||||
#define DMX_STATE_READY 3
|
||||
#define DMX_STATE_GO 4
|
||||
|
||||
#define DVB_DEMUX_MASK_MAX 18
|
||||
|
||||
#define MAX_PID 0x1fff
|
||||
|
||||
#define SPEED_PKTS_INTERVAL 50000
|
||||
|
||||
struct dvb_demux_filter {
|
||||
struct dmx_section_filter filter;
|
||||
u8 maskandmode[DMX_MAX_FILTER_SIZE];
|
||||
u8 maskandnotmode[DMX_MAX_FILTER_SIZE];
|
||||
int doneq;
|
||||
|
||||
struct dvb_demux_filter *next;
|
||||
struct dvb_demux_feed *feed;
|
||||
int index;
|
||||
int state;
|
||||
int type;
|
||||
|
||||
u16 hw_handle;
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
#define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head)
|
||||
|
||||
struct dvb_demux_feed {
|
||||
union {
|
||||
struct dmx_ts_feed ts;
|
||||
struct dmx_section_feed sec;
|
||||
} feed;
|
||||
|
||||
union {
|
||||
dmx_ts_cb ts;
|
||||
dmx_section_cb sec;
|
||||
} cb;
|
||||
|
||||
struct dvb_demux *demux;
|
||||
void *priv;
|
||||
int type;
|
||||
int state;
|
||||
u16 pid;
|
||||
|
||||
ktime_t timeout;
|
||||
struct dvb_demux_filter *filter;
|
||||
|
||||
int ts_type;
|
||||
enum dmx_ts_pes pes_type;
|
||||
|
||||
int cc;
|
||||
int pusi_seen; /* prevents feeding of garbage from previous section */
|
||||
|
||||
u16 peslen;
|
||||
|
||||
struct list_head list_head;
|
||||
unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */
|
||||
};
|
||||
|
||||
struct dvb_demux {
|
||||
struct dmx_demux dmx;
|
||||
void *priv;
|
||||
int filternum;
|
||||
int feednum;
|
||||
int (*start_feed)(struct dvb_demux_feed *feed);
|
||||
int (*stop_feed)(struct dvb_demux_feed *feed);
|
||||
int (*write_to_decoder)(struct dvb_demux_feed *feed,
|
||||
const u8 *buf, size_t len);
|
||||
u32 (*check_crc32)(struct dvb_demux_feed *feed,
|
||||
const u8 *buf, size_t len);
|
||||
void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst,
|
||||
const u8 *src, size_t len);
|
||||
|
||||
int users;
|
||||
#define MAX_DVB_DEMUX_USERS 10
|
||||
struct dvb_demux_filter *filter;
|
||||
struct dvb_demux_feed *feed;
|
||||
|
||||
struct list_head frontend_list;
|
||||
|
||||
struct dvb_demux_feed *pesfilter[DMX_PES_OTHER];
|
||||
u16 pids[DMX_PES_OTHER];
|
||||
int playing;
|
||||
int recording;
|
||||
|
||||
#define DMX_MAX_PID 0x2000
|
||||
struct list_head feed_list;
|
||||
u8 tsbuf[204];
|
||||
int tsbufp;
|
||||
|
||||
struct mutex mutex;
|
||||
spinlock_t lock;
|
||||
|
||||
uint8_t *cnt_storage; /* for TS continuity check */
|
||||
|
||||
ktime_t speed_last_time; /* for TS speed check */
|
||||
uint32_t speed_pkts_cnt; /* for TS speed check */
|
||||
};
|
||||
|
||||
int dvb_dmx_init(struct dvb_demux *dvbdemux);
|
||||
void dvb_dmx_release(struct dvb_demux *dvbdemux);
|
||||
void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf,
|
||||
size_t count);
|
||||
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
|
||||
void dvb_dmx_swfilter_204(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);
|
||||
|
||||
#endif /* _DVB_DEMUX_H_ */
|
@@ -1,246 +0,0 @@
|
||||
/*
|
||||
* dvb_filter.h
|
||||
*
|
||||
* Copyright (C) 2003 Convergence GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _DVB_FILTER_H_
|
||||
#define _DVB_FILTER_H_
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "demux.h"
|
||||
|
||||
typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *);
|
||||
|
||||
struct dvb_filter_pes2ts {
|
||||
unsigned char buf[188];
|
||||
unsigned char cc;
|
||||
dvb_filter_pes2ts_cb_t *cb;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
|
||||
dvb_filter_pes2ts_cb_t *cb, void *priv);
|
||||
|
||||
int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
|
||||
int len, int payload_start);
|
||||
|
||||
|
||||
#define PROG_STREAM_MAP 0xBC
|
||||
#define PRIVATE_STREAM1 0xBD
|
||||
#define PADDING_STREAM 0xBE
|
||||
#define PRIVATE_STREAM2 0xBF
|
||||
#define AUDIO_STREAM_S 0xC0
|
||||
#define AUDIO_STREAM_E 0xDF
|
||||
#define VIDEO_STREAM_S 0xE0
|
||||
#define VIDEO_STREAM_E 0xEF
|
||||
#define ECM_STREAM 0xF0
|
||||
#define EMM_STREAM 0xF1
|
||||
#define DSM_CC_STREAM 0xF2
|
||||
#define ISO13522_STREAM 0xF3
|
||||
#define PROG_STREAM_DIR 0xFF
|
||||
|
||||
#define DVB_PICTURE_START 0x00
|
||||
#define DVB_USER_START 0xb2
|
||||
#define DVB_SEQUENCE_HEADER 0xb3
|
||||
#define DVB_SEQUENCE_ERROR 0xb4
|
||||
#define DVB_EXTENSION_START 0xb5
|
||||
#define DVB_SEQUENCE_END 0xb7
|
||||
#define DVB_GOP_START 0xb8
|
||||
#define DVB_EXCEPT_SLICE 0xb0
|
||||
|
||||
#define SEQUENCE_EXTENSION 0x01
|
||||
#define SEQUENCE_DISPLAY_EXTENSION 0x02
|
||||
#define PICTURE_CODING_EXTENSION 0x08
|
||||
#define QUANT_MATRIX_EXTENSION 0x03
|
||||
#define PICTURE_DISPLAY_EXTENSION 0x07
|
||||
|
||||
#define I_FRAME 0x01
|
||||
#define B_FRAME 0x02
|
||||
#define P_FRAME 0x03
|
||||
|
||||
/* Initialize sequence_data */
|
||||
#define INIT_HORIZONTAL_SIZE 720
|
||||
#define INIT_VERTICAL_SIZE 576
|
||||
#define INIT_ASPECT_RATIO 0x02
|
||||
#define INIT_FRAME_RATE 0x03
|
||||
#define INIT_DISP_HORIZONTAL_SIZE 540
|
||||
#define INIT_DISP_VERTICAL_SIZE 576
|
||||
|
||||
|
||||
//flags2
|
||||
#define PTS_DTS_FLAGS 0xC0
|
||||
#define ESCR_FLAG 0x20
|
||||
#define ES_RATE_FLAG 0x10
|
||||
#define DSM_TRICK_FLAG 0x08
|
||||
#define ADD_CPY_FLAG 0x04
|
||||
#define PES_CRC_FLAG 0x02
|
||||
#define PES_EXT_FLAG 0x01
|
||||
|
||||
//pts_dts flags
|
||||
#define PTS_ONLY 0x80
|
||||
#define PTS_DTS 0xC0
|
||||
|
||||
#define TS_SIZE 188
|
||||
#define TRANS_ERROR 0x80
|
||||
#define PAY_START 0x40
|
||||
#define TRANS_PRIO 0x20
|
||||
#define PID_MASK_HI 0x1F
|
||||
//flags
|
||||
#define TRANS_SCRMBL1 0x80
|
||||
#define TRANS_SCRMBL2 0x40
|
||||
#define ADAPT_FIELD 0x20
|
||||
#define PAYLOAD 0x10
|
||||
#define COUNT_MASK 0x0F
|
||||
|
||||
// adaptation flags
|
||||
#define DISCON_IND 0x80
|
||||
#define RAND_ACC_IND 0x40
|
||||
#define ES_PRI_IND 0x20
|
||||
#define PCR_FLAG 0x10
|
||||
#define OPCR_FLAG 0x08
|
||||
#define SPLICE_FLAG 0x04
|
||||
#define TRANS_PRIV 0x02
|
||||
#define ADAP_EXT_FLAG 0x01
|
||||
|
||||
// adaptation extension flags
|
||||
#define LTW_FLAG 0x80
|
||||
#define PIECE_RATE 0x40
|
||||
#define SEAM_SPLICE 0x20
|
||||
|
||||
|
||||
#define MAX_PLENGTH 0xFFFF
|
||||
#define MMAX_PLENGTH (256*MAX_PLENGTH)
|
||||
|
||||
#ifndef IPACKS
|
||||
#define IPACKS 2048
|
||||
#endif
|
||||
|
||||
struct ipack {
|
||||
int size;
|
||||
int found;
|
||||
u8 *buf;
|
||||
u8 cid;
|
||||
u32 plength;
|
||||
u8 plen[2];
|
||||
u8 flag1;
|
||||
u8 flag2;
|
||||
u8 hlength;
|
||||
u8 pts[5];
|
||||
u16 *pid;
|
||||
int mpeg;
|
||||
u8 check;
|
||||
int which;
|
||||
int done;
|
||||
void *data;
|
||||
void (*func)(u8 *buf, int size, void *priv);
|
||||
int count;
|
||||
int repack_subids;
|
||||
};
|
||||
|
||||
struct dvb_video_info {
|
||||
u32 horizontal_size;
|
||||
u32 vertical_size;
|
||||
u32 aspect_ratio;
|
||||
u32 framerate;
|
||||
u32 video_format;
|
||||
u32 bit_rate;
|
||||
u32 comp_bit_rate;
|
||||
u32 vbv_buffer_size;
|
||||
s16 vbv_delay;
|
||||
u32 CSPF;
|
||||
u32 off;
|
||||
};
|
||||
|
||||
#define OFF_SIZE 4
|
||||
#define FIRST_FIELD 0
|
||||
#define SECOND_FIELD 1
|
||||
#define VIDEO_FRAME_PICTURE 0x03
|
||||
|
||||
struct mpg_picture {
|
||||
int channel;
|
||||
struct dvb_video_info vinfo;
|
||||
u32 *sequence_gop_header;
|
||||
u32 *picture_header;
|
||||
s32 time_code;
|
||||
int low_delay;
|
||||
int closed_gop;
|
||||
int broken_link;
|
||||
int sequence_header_flag;
|
||||
int gop_flag;
|
||||
int sequence_end_flag;
|
||||
|
||||
u8 profile_and_level;
|
||||
s32 picture_coding_parameter;
|
||||
u32 matrix[32];
|
||||
s8 matrix_change_flag;
|
||||
|
||||
u8 picture_header_parameter;
|
||||
/* bit 0 - 2: bwd f code
|
||||
bit 3 : fpb vector
|
||||
bit 4 - 6: fwd f code
|
||||
bit 7 : fpf vector */
|
||||
|
||||
int mpeg1_flag;
|
||||
int progressive_sequence;
|
||||
int sequence_display_extension_flag;
|
||||
u32 sequence_header_data;
|
||||
s16 last_frame_centre_horizontal_offset;
|
||||
s16 last_frame_centre_vertical_offset;
|
||||
|
||||
u32 pts[2]; /* [0] 1st field, [1] 2nd field */
|
||||
int top_field_first;
|
||||
int repeat_first_field;
|
||||
int progressive_frame;
|
||||
int bank;
|
||||
int forward_bank;
|
||||
int backward_bank;
|
||||
int compress;
|
||||
s16 frame_centre_horizontal_offset[OFF_SIZE];
|
||||
/* [0-2] 1st field, [3] 2nd field */
|
||||
s16 frame_centre_vertical_offset[OFF_SIZE];
|
||||
/* [0-2] 1st field, [3] 2nd field */
|
||||
s16 temporal_reference[2];
|
||||
/* [0] 1st field, [1] 2nd field */
|
||||
|
||||
s8 picture_coding_type[2];
|
||||
/* [0] 1st field, [1] 2nd field */
|
||||
s8 picture_structure[2];
|
||||
/* [0] 1st field, [1] 2nd field */
|
||||
s8 picture_display_extension_flag[2];
|
||||
/* [0] 1st field, [1] 2nd field */
|
||||
/* picture_display_extenion() 0:no 1:exit*/
|
||||
s8 pts_flag[2];
|
||||
/* [0] 1st field, [1] 2nd field */
|
||||
};
|
||||
|
||||
struct dvb_audio_info {
|
||||
int layer;
|
||||
u32 bit_rate;
|
||||
u32 frequency;
|
||||
u32 mode;
|
||||
u32 mode_extension ;
|
||||
u32 emphasis;
|
||||
u32 framesize;
|
||||
u32 off;
|
||||
};
|
||||
|
||||
int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr);
|
||||
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@@ -1,817 +0,0 @@
|
||||
/*
|
||||
* 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) 2004 convergence GmbH
|
||||
*
|
||||
* Written by Ralph Metzler
|
||||
* Overhauled by Holger Waechtler
|
||||
* Kernel I2C stuff by Michael Hunold <hunold@convergence.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DVB_FRONTEND_H_
|
||||
#define _DVB_FRONTEND_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/version.h>
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0))
|
||||
#include <linux/sched/signal.h>
|
||||
#else
|
||||
#include <linux/sched.h>
|
||||
#endif
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
#include "dvbdev.h"
|
||||
|
||||
/*
|
||||
* Maximum number of Delivery systems per frontend. It
|
||||
* should be smaller or equal to 32
|
||||
*/
|
||||
#define MAX_DELSYS 16
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
int min_delay_ms;
|
||||
int step_size;
|
||||
int max_drift;
|
||||
};
|
||||
|
||||
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 {
|
||||
char name[128];
|
||||
|
||||
u32 frequency_min;
|
||||
u32 frequency_max;
|
||||
u32 frequency_step;
|
||||
|
||||
u32 bandwidth_min;
|
||||
u32 bandwidth_max;
|
||||
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 {
|
||||
unsigned int frequency;
|
||||
unsigned int mode;
|
||||
unsigned int audmode;
|
||||
u64 std;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dvbfe_algo - defines the algorithm used to tune into a channel
|
||||
*
|
||||
* @DVBFE_ALGO_HW: Hardware Algorithm -
|
||||
* Devices that support this algorithm do everything in hardware
|
||||
* and no software support is needed to handle them.
|
||||
* Requesting these devices to LOCK is the only thing required,
|
||||
* device is supposed to do everything in the hardware.
|
||||
*
|
||||
* @DVBFE_ALGO_SW: Software Algorithm -
|
||||
* These are dumb devices, that require software to do everything
|
||||
*
|
||||
* @DVBFE_ALGO_CUSTOM: Customizable Agorithm -
|
||||
* Devices having this algorithm can be customized to have specific
|
||||
* algorithms in the frontend driver, rather than simply doing a
|
||||
* software zig-zag. In this case the zigzag maybe hardware assisted
|
||||
* or it maybe completely done in hardware. In all cases, usage of
|
||||
* this algorithm, in conjunction with the search and track
|
||||
* callbacks, utilizes the driver specific algorithm.
|
||||
*
|
||||
* @DVBFE_ALGO_RECOVERY: Recovery Algorithm -
|
||||
* These devices have AUTO recovery capabilities from LOCK failure
|
||||
*/
|
||||
enum dvbfe_algo {
|
||||
DVBFE_ALGO_HW = (1 << 0),
|
||||
DVBFE_ALGO_SW = (1 << 1),
|
||||
DVBFE_ALGO_CUSTOM = (1 << 2),
|
||||
DVBFE_ALGO_RECOVERY = (1 << 31)
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dvbfe_search - search callback possible return status
|
||||
*
|
||||
* @DVBFE_ALGO_SEARCH_SUCCESS:
|
||||
* The frontend search algorithm completed and returned successfully
|
||||
*
|
||||
* @DVBFE_ALGO_SEARCH_ASLEEP:
|
||||
* The frontend search algorithm is sleeping
|
||||
*
|
||||
* @DVBFE_ALGO_SEARCH_FAILED:
|
||||
* The frontend search for a signal failed
|
||||
*
|
||||
* @DVBFE_ALGO_SEARCH_INVALID:
|
||||
* The frontend search algorith was probably supplied with invalid
|
||||
* parameters and the search is an invalid one
|
||||
*
|
||||
* @DVBFE_ALGO_SEARCH_ERROR:
|
||||
* The frontend search algorithm failed due to some error
|
||||
*
|
||||
* @DVBFE_ALGO_SEARCH_AGAIN:
|
||||
* The frontend search algorithm was requested to search again
|
||||
*/
|
||||
enum dvbfe_search {
|
||||
DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0),
|
||||
DVBFE_ALGO_SEARCH_ASLEEP = (1 << 1),
|
||||
DVBFE_ALGO_SEARCH_FAILED = (1 << 2),
|
||||
DVBFE_ALGO_SEARCH_INVALID = (1 << 3),
|
||||
DVBFE_ALGO_SEARCH_AGAIN = (1 << 4),
|
||||
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_info info;
|
||||
|
||||
void (*release)(struct dvb_frontend *fe);
|
||||
int (*init)(struct dvb_frontend *fe);
|
||||
int (*sleep)(struct dvb_frontend *fe);
|
||||
int (*suspend)(struct dvb_frontend *fe);
|
||||
int (*resume)(struct dvb_frontend *fe);
|
||||
|
||||
/* This is the recomended way to set the tuner */
|
||||
int (*set_params)(struct dvb_frontend *fe);
|
||||
int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
|
||||
|
||||
int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
|
||||
|
||||
int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
|
||||
int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
|
||||
int (*get_if_frequency)(struct dvb_frontend *fe, u32 *frequency);
|
||||
|
||||
#define TUNER_STATUS_LOCKED 1
|
||||
#define TUNER_STATUS_STEREO 2
|
||||
int (*get_status)(struct dvb_frontend *fe, u32 *status);
|
||||
int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
|
||||
int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
|
||||
|
||||
/*
|
||||
* This is support for demods like the mt352 - fills out the supplied
|
||||
* buffer with what to write.
|
||||
*
|
||||
* 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 tuners which require sophisticated tuning loops,
|
||||
* controlling each parameter separately.
|
||||
*
|
||||
* Don't use on newer drivers.
|
||||
*/
|
||||
int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
|
||||
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 {
|
||||
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_info info;
|
||||
|
||||
void (*set_params)(struct dvb_frontend *fe,
|
||||
struct analog_parameters *params);
|
||||
int (*has_signal)(struct dvb_frontend *fe, u16 *signal);
|
||||
int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
|
||||
void (*tuner_status)(struct dvb_frontend *fe);
|
||||
void (*standby)(struct dvb_frontend *fe);
|
||||
void (*release)(struct dvb_frontend *fe);
|
||||
int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable);
|
||||
|
||||
/** This is to allow setting tuner-specific configuration */
|
||||
int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
|
||||
};
|
||||
|
||||
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_info info;
|
||||
|
||||
u8 delsys[MAX_DELSYS];
|
||||
|
||||
void (*detach)(struct dvb_frontend *fe);
|
||||
void (*release)(struct dvb_frontend* fe);
|
||||
void (*release_sec)(struct dvb_frontend* fe);
|
||||
|
||||
int (*init)(struct dvb_frontend* fe);
|
||||
int (*sleep)(struct dvb_frontend* fe);
|
||||
|
||||
int (*write)(struct dvb_frontend* fe, const u8 buf[], int len);
|
||||
|
||||
/* if this is set, it overrides the default swzigzag */
|
||||
int (*tune)(struct dvb_frontend* fe,
|
||||
bool re_tune,
|
||||
unsigned int mode_flags,
|
||||
unsigned int *delay,
|
||||
enum fe_status *status);
|
||||
|
||||
/* get frontend tuning algorithm from the module */
|
||||
enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
|
||||
|
||||
/* these two are only used for the swzigzag code */
|
||||
int (*set_frontend)(struct dvb_frontend *fe);
|
||||
int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
|
||||
|
||||
int (*get_frontend)(struct dvb_frontend *fe,
|
||||
struct dtv_frontend_properties *props);
|
||||
|
||||
int (*read_status)(struct dvb_frontend *fe, enum fe_status *status);
|
||||
int (*read_ber)(struct dvb_frontend* fe, u32* ber);
|
||||
int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
|
||||
int (*read_snr)(struct dvb_frontend* fe, u16* snr);
|
||||
int (*read_ucblocks)(struct dvb_frontend* fe, u32* ucblocks);
|
||||
|
||||
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_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply);
|
||||
int (*diseqc_send_burst)(struct dvb_frontend *fe,
|
||||
enum fe_sec_mini_cmd minicmd);
|
||||
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 (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
|
||||
int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
|
||||
int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
|
||||
int (*set_lna)(struct dvb_frontend *);
|
||||
int (*set_input)(struct dvb_frontend *, int);
|
||||
|
||||
/*
|
||||
* These callbacks are for devices that implement their own
|
||||
* tuning algorithms, rather than a simple swzigzag
|
||||
*/
|
||||
enum dvbfe_search (*search)(struct dvb_frontend *fe);
|
||||
|
||||
struct dvb_tuner_ops tuner_ops;
|
||||
struct analog_demod_ops analog_ops;
|
||||
|
||||
int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
|
||||
int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
|
||||
|
||||
u8 xbar[3];
|
||||
};
|
||||
|
||||
#ifdef __DVB_CORE__
|
||||
#define MAX_EVENT 8
|
||||
|
||||
/* Used only internally at dvb_frontend.c */
|
||||
struct dvb_fe_events {
|
||||
struct dvb_frontend_event events[MAX_EVENT];
|
||||
int eventw;
|
||||
int eventr;
|
||||
int overflow;
|
||||
wait_queue_head_t wait_queue;
|
||||
struct mutex mtx;
|
||||
};
|
||||
#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).
|
||||
* @scrambling_sequence_index: Carries the index of the DVB-S2 physical layer
|
||||
* scrambling sequence.
|
||||
* @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 {
|
||||
u32 frequency;
|
||||
enum fe_modulation modulation;
|
||||
|
||||
enum fe_sec_voltage voltage;
|
||||
enum fe_sec_tone_mode sectone;
|
||||
enum fe_spectral_inversion inversion;
|
||||
enum fe_code_rate fec_inner;
|
||||
enum fe_transmit_mode transmission_mode;
|
||||
u32 bandwidth_hz; /* 0 = AUTO */
|
||||
enum fe_guard_interval guard_interval;
|
||||
enum fe_hierarchy hierarchy;
|
||||
u32 symbol_rate;
|
||||
enum fe_code_rate code_rate_HP;
|
||||
enum fe_code_rate code_rate_LP;
|
||||
|
||||
enum fe_pilot pilot;
|
||||
enum fe_rolloff rolloff;
|
||||
|
||||
enum fe_delivery_system delivery_system;
|
||||
|
||||
enum fe_interleaving interleaving;
|
||||
|
||||
/* ISDB-T specifics */
|
||||
u8 isdbt_partial_reception;
|
||||
u8 isdbt_sb_mode;
|
||||
u8 isdbt_sb_subchannel;
|
||||
u32 isdbt_sb_segment_idx;
|
||||
u32 isdbt_sb_segment_count;
|
||||
u8 isdbt_layer_enabled;
|
||||
struct {
|
||||
u8 segment_count;
|
||||
enum fe_code_rate fec;
|
||||
enum fe_modulation modulation;
|
||||
u8 interleaving;
|
||||
} layer[3];
|
||||
|
||||
/* Multistream specifics */
|
||||
u32 stream_id;
|
||||
|
||||
/* Physical Layer Scrambling specifics */
|
||||
u32 scrambling_sequence_index;
|
||||
|
||||
/* ATSC-MH specifics */
|
||||
u8 atscmh_fic_ver;
|
||||
u8 atscmh_parade_id;
|
||||
u8 atscmh_nog;
|
||||
u8 atscmh_tnog;
|
||||
u8 atscmh_sgn;
|
||||
u8 atscmh_prc;
|
||||
|
||||
u8 atscmh_rs_frame_mode;
|
||||
u8 atscmh_rs_frame_ensemble;
|
||||
u8 atscmh_rs_code_mode_pri;
|
||||
u8 atscmh_rs_code_mode_sec;
|
||||
u8 atscmh_sccc_block_mode;
|
||||
u8 atscmh_sccc_code_mode_a;
|
||||
u8 atscmh_sccc_code_mode_b;
|
||||
u8 atscmh_sccc_code_mode_c;
|
||||
u8 atscmh_sccc_code_mode_d;
|
||||
|
||||
u32 lna;
|
||||
s32 input;
|
||||
|
||||
/* statistics data */
|
||||
struct dtv_fe_stats strength;
|
||||
struct dtv_fe_stats cnr;
|
||||
struct dtv_fe_stats pre_bit_error;
|
||||
struct dtv_fe_stats pre_bit_count;
|
||||
struct dtv_fe_stats post_bit_error;
|
||||
struct dtv_fe_stats post_bit_count;
|
||||
struct dtv_fe_stats block_error;
|
||||
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 kref refcount;
|
||||
struct dvb_frontend_ops ops;
|
||||
struct dvb_adapter *dvb;
|
||||
void *demodulator_priv;
|
||||
void *tuner_priv;
|
||||
void *frontend_priv;
|
||||
void *sec_priv;
|
||||
void *analog_demod_priv;
|
||||
struct dtv_frontend_properties dtv_property_cache;
|
||||
#define DVB_FRONTEND_COMPONENT_TUNER 0
|
||||
#define DVB_FRONTEND_COMPONENT_DEMOD 1
|
||||
int (*callback)(void *adapter_priv, int component, int cmd, int arg);
|
||||
int id;
|
||||
unsigned int exit;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* dvb_frontend_suspend() - Suspends a Digital TV frontend
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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
|
@@ -19,7 +19,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/bug.h>
|
||||
#include "dvb_math.h"
|
||||
#include <media/dvb_math.h>
|
||||
|
||||
static const unsigned short logtable[256] = {
|
||||
0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
|
||||
|
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* dvb-math provides some complex fixed-point math
|
||||
* operations shared between the dvb related stuff
|
||||
*
|
||||
* Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __DVB_MATH_H
|
||||
#define __DVB_MATH_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/**
|
||||
* 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:
|
||||
*
|
||||
* intlog2(value) = intlog2(value * 2^x) - x * 2^24
|
||||
*
|
||||
* Some usecase examples:
|
||||
*
|
||||
* intlog2(8) will give 3 << 24 = 3 * 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);
|
||||
|
||||
/**
|
||||
* 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:
|
||||
*
|
||||
* intlog10(value) = intlog10(value * 10^x) - x * 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
|
||||
*
|
||||
* look at intlog2 for similar examples
|
||||
*
|
||||
* return: log10(value) * 2^24
|
||||
*/
|
||||
extern unsigned int intlog10(u32 value);
|
||||
|
||||
#endif
|
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* dvb_net.c
|
||||
*
|
||||
@@ -13,18 +14,6 @@
|
||||
* and Wolfram Stering <wstering@cosy.sbg.ac.at>
|
||||
*
|
||||
* ULE Decaps according to RFC 4326.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* To obtain the license, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -38,7 +27,7 @@
|
||||
* Competence Center for Advanced Satellite Communications.
|
||||
* Bugfixes and robustness improvements.
|
||||
* Filtering on dest MAC addresses, if present (D-Bit = 0)
|
||||
* ULE_DEBUG compile-time option.
|
||||
* DVB_ULE_DEBUG compile-time option.
|
||||
* Apr 2006: cp v3: Bugfixes and compliency with RFC 4326 (ULE) by
|
||||
* Christian Praehauser <cpraehaus@cosy.sbg.ac.at>,
|
||||
* Paris Lodron University of Salzburg.
|
||||
@@ -69,8 +58,8 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "dvb_demux.h"
|
||||
#include "dvb_net.h"
|
||||
#include <media/dvb_demux.h>
|
||||
#include <media/dvb_net.h>
|
||||
|
||||
static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
|
||||
{
|
||||
@@ -83,15 +72,20 @@ static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
|
||||
|
||||
#define DVB_NET_MULTICAST_MAX 10
|
||||
|
||||
#undef ULE_DEBUG
|
||||
#undef DVB_ULE_DEBUG
|
||||
|
||||
#ifdef ULE_DEBUG
|
||||
#ifdef DVB_ULE_DEBUG
|
||||
/*
|
||||
* The code inside DVB_ULE_DEBUG keeps a history of the
|
||||
* last 100 TS cells processed.
|
||||
*/
|
||||
static unsigned char ule_hist[100*TS_SZ] = { 0 };
|
||||
static unsigned char *ule_where = ule_hist, ule_dump;
|
||||
|
||||
static void hexdump(const unsigned char *buf, unsigned short len)
|
||||
{
|
||||
print_hex_dump_debug("", DUMP_PREFIX_OFFSET, 16, 1, buf, len, true);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct dvb_net_priv {
|
||||
@@ -130,7 +124,7 @@ struct dvb_net_priv {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* Determine the packet's protocol ID. The rule here is that we
|
||||
* assume 802.3 if the type field is short enough to be a length.
|
||||
* This is normal practice and works for any 'now in use' protocol.
|
||||
@@ -160,7 +154,7 @@ static __be16 dvb_net_eth_type_trans(struct sk_buff *skb,
|
||||
|
||||
rawp = skb->data;
|
||||
|
||||
/**
|
||||
/*
|
||||
* This is a magic hack to spot IPX packets. Older Novell breaks
|
||||
* the protocol design and runs IPX over 802.3 without an 802.2 LLC
|
||||
* layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
|
||||
@@ -169,7 +163,7 @@ static __be16 dvb_net_eth_type_trans(struct sk_buff *skb,
|
||||
if (*(unsigned short *)rawp == 0xFFFF)
|
||||
return htons(ETH_P_802_3);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Real 802.2 LLC
|
||||
*/
|
||||
return htons(ETH_P_802_2);
|
||||
@@ -220,7 +214,8 @@ static int ule_exthdr_padding(struct dvb_net_priv *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Handle ULE extension headers.
|
||||
/*
|
||||
* Handle ULE extension headers.
|
||||
* Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding.
|
||||
* Returns: >= 0: nr. of bytes consumed by next extension header
|
||||
* -1: Mandatory extension header that is not recognized or TEST SNDU; discard.
|
||||
@@ -284,11 +279,9 @@ static int handle_ule_extensions( struct dvb_net_priv *p )
|
||||
if (l < 0)
|
||||
return l; /* Stop extension header processing and discard SNDU. */
|
||||
total_ext_len += l;
|
||||
#ifdef ULE_DEBUG
|
||||
pr_debug("ule_next_hdr=%p, ule_sndu_type=%i, l=%i, total_ext_len=%i\n",
|
||||
p->ule_next_hdr, (int)p->ule_sndu_type,
|
||||
l, total_ext_len);
|
||||
#endif
|
||||
|
||||
} while (p->ule_sndu_type < ETH_P_802_3_MIN);
|
||||
|
||||
@@ -296,7 +289,7 @@ static int handle_ule_extensions( struct dvb_net_priv *p )
|
||||
}
|
||||
|
||||
|
||||
/** Prepare for a new ULE SNDU: reset the decoder state. */
|
||||
/* Prepare for a new ULE SNDU: reset the decoder state. */
|
||||
static inline void reset_ule( struct dvb_net_priv *p )
|
||||
{
|
||||
p->ule_skb = NULL;
|
||||
@@ -309,7 +302,7 @@ static inline void reset_ule( struct dvb_net_priv *p )
|
||||
p->ule_bridged = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Decode ULE SNDUs according to draft-ietf-ipdvb-ule-03.txt from a sequence of
|
||||
* TS cells of a single PID.
|
||||
*/
|
||||
@@ -324,29 +317,21 @@ struct dvb_net_ule_handle {
|
||||
const u8 *ts, *ts_end, *from_where;
|
||||
u8 ts_remain, how_much, new_ts;
|
||||
bool error;
|
||||
#ifdef ULE_DEBUG
|
||||
/*
|
||||
* The code inside ULE_DEBUG keeps a history of the
|
||||
* last 100 TS cells processed.
|
||||
*/
|
||||
static unsigned char ule_hist[100*TS_SZ];
|
||||
static unsigned char *ule_where = ule_hist, ule_dump;
|
||||
#endif
|
||||
};
|
||||
|
||||
static int dvb_net_ule_new_ts_cell(struct dvb_net_ule_handle *h)
|
||||
{
|
||||
/* We are about to process a new TS cell. */
|
||||
|
||||
#ifdef ULE_DEBUG
|
||||
if (h->ule_where >= &h->ule_hist[100*TS_SZ])
|
||||
h->ule_where = h->ule_hist;
|
||||
memcpy(h->ule_where, h->ts, TS_SZ);
|
||||
if (h->ule_dump) {
|
||||
hexdump(h->ule_where, TS_SZ);
|
||||
h->ule_dump = 0;
|
||||
#ifdef DVB_ULE_DEBUG
|
||||
if (ule_where >= &ule_hist[100*TS_SZ])
|
||||
ule_where = ule_hist;
|
||||
memcpy(ule_where, h->ts, TS_SZ);
|
||||
if (ule_dump) {
|
||||
hexdump(ule_where, TS_SZ);
|
||||
ule_dump = 0;
|
||||
}
|
||||
h->ule_where += TS_SZ;
|
||||
ule_where += TS_SZ;
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -664,6 +649,7 @@ static int dvb_net_ule_should_drop(struct dvb_net_ule_handle *h)
|
||||
|
||||
|
||||
static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h,
|
||||
struct kvec iov[3],
|
||||
u32 ule_crc, u32 expected_crc)
|
||||
{
|
||||
u8 dest_addr[ETH_ALEN];
|
||||
@@ -676,22 +662,22 @@ static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h,
|
||||
h->ts_remain > 2 ?
|
||||
*(unsigned short *)h->from_where : 0);
|
||||
|
||||
#ifdef ULE_DEBUG
|
||||
#ifdef DVB_ULE_DEBUG
|
||||
hexdump(iov[0].iov_base, iov[0].iov_len);
|
||||
hexdump(iov[1].iov_base, iov[1].iov_len);
|
||||
hexdump(iov[2].iov_base, iov[2].iov_len);
|
||||
|
||||
if (h->ule_where == h->ule_hist) {
|
||||
hexdump(&h->ule_hist[98*TS_SZ], TS_SZ);
|
||||
hexdump(&h->ule_hist[99*TS_SZ], TS_SZ);
|
||||
} else if (h->ule_where == &h->ule_hist[TS_SZ]) {
|
||||
hexdump(&h->ule_hist[99*TS_SZ], TS_SZ);
|
||||
hexdump(h->ule_hist, TS_SZ);
|
||||
if (ule_where == ule_hist) {
|
||||
hexdump(&ule_hist[98*TS_SZ], TS_SZ);
|
||||
hexdump(&ule_hist[99*TS_SZ], TS_SZ);
|
||||
} else if (ule_where == &ule_hist[TS_SZ]) {
|
||||
hexdump(&ule_hist[99*TS_SZ], TS_SZ);
|
||||
hexdump(ule_hist, TS_SZ);
|
||||
} else {
|
||||
hexdump(h->ule_where - TS_SZ - TS_SZ, TS_SZ);
|
||||
hexdump(h->ule_where - TS_SZ, TS_SZ);
|
||||
hexdump(ule_where - TS_SZ - TS_SZ, TS_SZ);
|
||||
hexdump(ule_where - TS_SZ, TS_SZ);
|
||||
}
|
||||
h->ule_dump = 1;
|
||||
ule_dump = 1;
|
||||
#endif
|
||||
|
||||
h->dev->stats.rx_errors++;
|
||||
@@ -709,11 +695,9 @@ static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h,
|
||||
|
||||
if (!h->priv->ule_dbit) {
|
||||
if (dvb_net_ule_should_drop(h)) {
|
||||
#ifdef ULE_DEBUG
|
||||
netdev_dbg(h->dev,
|
||||
"Dropping SNDU: MAC destination address does not match: dest addr: %pM, h->dev addr: %pM\n",
|
||||
h->priv->ule_skb->data, h->dev->dev_addr);
|
||||
#endif
|
||||
dev_kfree_skb(h->priv->ule_skb);
|
||||
return;
|
||||
}
|
||||
@@ -784,6 +768,7 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len)
|
||||
struct dvb_net_ule_handle h = {
|
||||
.dev = dev,
|
||||
.priv = netdev_priv(dev),
|
||||
.ethh = NULL,
|
||||
.buf = buf,
|
||||
.buf_len = buf_len,
|
||||
.skipped = 0L,
|
||||
@@ -793,11 +778,7 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len)
|
||||
.ts_remain = 0,
|
||||
.how_much = 0,
|
||||
.new_ts = 1,
|
||||
.ethh = NULL,
|
||||
.error = false,
|
||||
#ifdef ULE_DEBUG
|
||||
.ule_where = ule_hist,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -869,7 +850,7 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len)
|
||||
*(tail - 2) << 8 |
|
||||
*(tail - 1);
|
||||
|
||||
dvb_net_ule_check_crc(&h, ule_crc, expected_crc);
|
||||
dvb_net_ule_check_crc(&h, iov, ule_crc, expected_crc);
|
||||
|
||||
/* Prepare for next SNDU. */
|
||||
reset_ule(h.priv);
|
||||
@@ -902,7 +883,8 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len)
|
||||
|
||||
static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len,
|
||||
const u8 *buffer2, size_t buffer2_len,
|
||||
struct dmx_ts_feed *feed)
|
||||
struct dmx_ts_feed *feed,
|
||||
u32 *buffer_flags)
|
||||
{
|
||||
struct net_device *dev = feed->priv;
|
||||
|
||||
@@ -1010,12 +992,12 @@ static void dvb_net_sec(struct net_device *dev,
|
||||
}
|
||||
|
||||
static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
|
||||
const u8 *buffer2, size_t buffer2_len,
|
||||
struct dmx_section_filter *filter)
|
||||
const u8 *buffer2, size_t buffer2_len,
|
||||
struct dmx_section_filter *filter, u32 *buffer_flags)
|
||||
{
|
||||
struct net_device *dev = filter->priv;
|
||||
|
||||
/**
|
||||
/*
|
||||
* we rely on the DVB API definition where exactly one complete
|
||||
* section is delivered in buffer1
|
||||
*/
|
||||
@@ -1023,7 +1005,7 @@ static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev)
|
||||
static netdev_tx_t dvb_net_tx(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
dev_kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
|
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* dvb_net.h
|
||||
*
|
||||
* Copyright (C) 2001 Ralph Metzler for convergence integrated media GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DVB_NET_H_
|
||||
#define _DVB_NET_H_
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include "dvbdev.h"
|
||||
|
||||
#define DVB_NET_DEVICES_MAX 10
|
||||
|
||||
#ifdef CONFIG_DVB_NET
|
||||
|
||||
struct dvb_net {
|
||||
struct dvb_device *dvbdev;
|
||||
struct net_device *device[DVB_NET_DEVICES_MAX];
|
||||
int state[DVB_NET_DEVICES_MAX];
|
||||
unsigned int exit:1;
|
||||
struct dmx_demux *demux;
|
||||
struct mutex ioctl_mutex;
|
||||
};
|
||||
|
||||
void dvb_net_release(struct dvb_net *);
|
||||
int dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *);
|
||||
|
||||
#else
|
||||
|
||||
struct dvb_net {
|
||||
struct dvb_device *dvbdev;
|
||||
};
|
||||
|
||||
static inline void dvb_net_release(struct dvb_net *dvbnet)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int dvb_net_init(struct dvb_adapter *adap,
|
||||
struct dvb_net *dvbnet, struct dmx_demux *dmx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* ifdef CONFIG_DVB_NET */
|
||||
|
||||
#endif
|
@@ -34,7 +34,7 @@
|
||||
#include <linux/uaccess.h>
|
||||
#endif
|
||||
|
||||
#include "dvb_ringbuffer.h"
|
||||
#include <media/dvb_ringbuffer.h>
|
||||
|
||||
#define PKT_READY 0
|
||||
#define PKT_DISPOSED 1
|
||||
@@ -63,7 +63,7 @@ int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
|
||||
* 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
|
||||
* for memory barriers also see Documentation/core-api/circular-buffers.txt
|
||||
*/
|
||||
return (rbuf->pread == smp_load_acquire(&rbuf->pwrite));
|
||||
#endif
|
||||
|
@@ -1,280 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* dvb_ringbuffer.h: ring buffer implementation for the dvb driver
|
||||
*
|
||||
* Copyright (C) 2003 Oliver Endriss
|
||||
* Copyright (C) 2004 Andrew de Quincey
|
||||
*
|
||||
* based on code originally found in av7110.c & dvb_ci.c:
|
||||
* Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler
|
||||
* for convergence integrated media GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _DVB_RINGBUFFER_H_
|
||||
#define _DVB_RINGBUFFER_H_
|
||||
|
||||
#include <linux/spinlock.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 {
|
||||
u8 *data;
|
||||
ssize_t size;
|
||||
ssize_t pread;
|
||||
ssize_t pwrite;
|
||||
int error;
|
||||
|
||||
wait_queue_head_t queue;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
#define DVB_RINGBUFFER_PKTHDRSIZE 3
|
||||
|
||||
/**
|
||||
* dvb_ringbuffer_init - initialize ring buffer, lock and queue
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
* @data: pointer to the buffer where the data will be stored
|
||||
* @len: bytes from ring buffer into @buf
|
||||
*/
|
||||
extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* dvb_ringbuffer_empty - test whether buffer is empty
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
*/
|
||||
extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* dvb_ringbuffer_reset - resets the ringbuffer to initial state
|
||||
*
|
||||
* @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);
|
||||
|
||||
/*
|
||||
* read routines & macros
|
||||
*/
|
||||
|
||||
/**
|
||||
* dvb_ringbuffer_flush - flush buffer
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
*/
|
||||
extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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) \
|
||||
((rbuf)->data[((rbuf)->pread + (offs)) % (rbuf)->size])
|
||||
|
||||
/**
|
||||
* DVB_RINGBUFFER_SKIP - advance read ptr by @num bytes
|
||||
*
|
||||
* @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;\
|
||||
}
|
||||
|
||||
/**
|
||||
* dvb_ringbuffer_read_user - Reads a buffer into a user 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 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,
|
||||
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,
|
||||
u8 *buf, size_t len);
|
||||
|
||||
/*
|
||||
* write routines & macros
|
||||
*/
|
||||
|
||||
/**
|
||||
* DVB_RINGBUFFER_WRITE_BYTE - write single byte to ring buffer
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
* @byte: byte to write
|
||||
*/
|
||||
#define DVB_RINGBUFFER_WRITE_BYTE(rbuf, byte) \
|
||||
{ (rbuf)->data[(rbuf)->pwrite] = (byte); \
|
||||
(rbuf)->pwrite = ((rbuf)->pwrite + 1) % (rbuf)->size; }
|
||||
|
||||
/**
|
||||
* dvb_ringbuffer_write - Writes a buffer into the ringbuffer
|
||||
*
|
||||
* @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,
|
||||
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);
|
||||
|
||||
/**
|
||||
* dvb_ringbuffer_pkt_write - Write a packet into the ringbuffer.
|
||||
*
|
||||
* @rbuf: Ringbuffer to write to.
|
||||
* @buf: Buffer to write.
|
||||
* @len: Length of buffer (currently limited to 65535 bytes max).
|
||||
*
|
||||
* Return: Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8 *buf,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* dvb_ringbuffer_pkt_read_user - Read from a packet 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.
|
||||
*
|
||||
* .. 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(struct dvb_ringbuffer *rbuf, size_t idx,
|
||||
int offset, u8 *buf, size_t len);
|
||||
|
||||
/**
|
||||
* dvb_ringbuffer_pkt_dispose - Dispose of a packet in the ring buffer.
|
||||
*
|
||||
* @rbuf: Ring buffer concerned.
|
||||
* @idx: Packet index as returned by dvb_ringbuffer_pkt_next().
|
||||
*/
|
||||
extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx);
|
||||
|
||||
/**
|
||||
* dvb_ringbuffer_pkt_next - Get the index of the next packet in a ringbuffer.
|
||||
*
|
||||
* @rbuf: Ringbuffer concerned.
|
||||
* @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.
|
||||
* 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);
|
||||
|
||||
#endif /* _DVB_RINGBUFFER_H_ */
|
@@ -24,6 +24,7 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
@@ -31,7 +32,7 @@
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/version.h>
|
||||
#include "dvbdev.h"
|
||||
#include <media/dvbdev.h>
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,0,0))
|
||||
/* Due to enum tuner_pad_index */
|
||||
@@ -54,8 +55,19 @@ static LIST_HEAD(dvb_adapter_list);
|
||||
static DEFINE_MUTEX(dvbdev_register_lock);
|
||||
|
||||
static const char * const dnames[] = {
|
||||
"video", "audio", "sec", "frontend", "demux", "dvr", "ca",
|
||||
"net", "osd", "ci", "mod", "ns", "nsd"
|
||||
[DVB_DEVICE_VIDEO] = "video",
|
||||
[DVB_DEVICE_AUDIO] = "audio",
|
||||
[DVB_DEVICE_SEC] = "sec",
|
||||
[DVB_DEVICE_FRONTEND] = "frontend",
|
||||
[DVB_DEVICE_DEMUX] = "demux",
|
||||
[DVB_DEVICE_DVR] = "dvr",
|
||||
[DVB_DEVICE_CA] = "ca",
|
||||
[DVB_DEVICE_NET] = "net",
|
||||
[DVB_DEVICE_OSD] = "osd",
|
||||
[DVB_DEVICE_CI] = "ci",
|
||||
[DVB_DEVICE_MOD] = "mod",
|
||||
[DVB_DEVICE_NS] = "ns",
|
||||
[DVB_DEVICE_NSD] = "nsd",
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DVB_DYNAMIC_MINORS
|
||||
@@ -63,7 +75,22 @@ static const char * const dnames[] = {
|
||||
#define DVB_MAX_IDS MAX_DVB_MINORS
|
||||
#else
|
||||
#define DVB_MAX_IDS 4
|
||||
#define nums2minor(num, type, id) ((num << 6) | (id << 4) | type)
|
||||
|
||||
static const u8 minor_type[] = {
|
||||
[DVB_DEVICE_VIDEO] = 0,
|
||||
[DVB_DEVICE_AUDIO] = 1,
|
||||
[DVB_DEVICE_SEC] = 2,
|
||||
[DVB_DEVICE_FRONTEND] = 3,
|
||||
[DVB_DEVICE_DEMUX] = 4,
|
||||
[DVB_DEVICE_DVR] = 5,
|
||||
[DVB_DEVICE_CA] = 6,
|
||||
[DVB_DEVICE_NET] = 7,
|
||||
[DVB_DEVICE_OSD] = 8,
|
||||
};
|
||||
|
||||
#define nums2minor(num, type, id) \
|
||||
(((num) << 6) | ((id) << 4) | minor_type[type])
|
||||
|
||||
#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
|
||||
#endif
|
||||
|
||||
@@ -319,8 +346,10 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev,
|
||||
if (npads) {
|
||||
dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads),
|
||||
GFP_KERNEL);
|
||||
if (!dvbdev->pads)
|
||||
if (!dvbdev->pads){
|
||||
kfree(dvbdev->entity);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
@@ -420,8 +449,10 @@ static int dvb_register_media_device(struct dvb_device *dvbdev,
|
||||
if (!dvbdev->entity)
|
||||
return 0;
|
||||
|
||||
link = media_create_intf_link(dvbdev->entity, &dvbdev->intf_devnode->intf,
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
link = media_create_intf_link(dvbdev->entity,
|
||||
&dvbdev->intf_devnode->intf,
|
||||
MEDIA_LNK_FL_ENABLED |
|
||||
MEDIA_LNK_FL_IMMUTABLE);
|
||||
if (!link)
|
||||
return -ENOMEM;
|
||||
#endif
|
||||
@@ -429,8 +460,8 @@ static int dvb_register_media_device(struct dvb_device *dvbdev,
|
||||
}
|
||||
|
||||
int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
const struct dvb_device *template, void *priv, int type,
|
||||
int demux_sink_pads)
|
||||
const struct dvb_device *template, void *priv,
|
||||
enum dvb_device_type type, int demux_sink_pads)
|
||||
{
|
||||
struct dvb_device *dvbdev;
|
||||
struct file_operations *dvbdevfops;
|
||||
@@ -454,7 +485,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
|
||||
dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
|
||||
|
||||
if (!dvbdevfops){
|
||||
kfree (dvbdev);
|
||||
@@ -470,7 +501,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
dvbdev->fops = dvbdevfops;
|
||||
init_waitqueue_head (&dvbdev->wait_queue);
|
||||
|
||||
memcpy(dvbdevfops, template->fops, sizeof(struct file_operations));
|
||||
dvbdevfops->owner = adap->module;
|
||||
|
||||
list_add_tail (&dvbdev->list_head, &adap->device_list);
|
||||
@@ -504,7 +534,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
dvb_media_device_free(dvbdev);
|
||||
kfree(dvbdevfops);
|
||||
kfree(dvbdev);
|
||||
up_write(&minor_rwsem);
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
return ret;
|
||||
}
|
||||
@@ -579,7 +608,8 @@ static int dvb_create_io_intf_links(struct dvb_adapter *adap,
|
||||
if (strncmp(entity->name, name, strlen(name)))
|
||||
continue;
|
||||
link = media_create_intf_link(entity, intf,
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
MEDIA_LNK_FL_ENABLED |
|
||||
MEDIA_LNK_FL_IMMUTABLE);
|
||||
if (!link)
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -598,8 +628,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
|
||||
unsigned demux_pad = 0;
|
||||
unsigned dvr_pad = 0;
|
||||
unsigned ntuner = 0, ndemod = 0;
|
||||
u16 source_pad = 0;
|
||||
int ret;
|
||||
int ret, pad_source, pad_sink;
|
||||
static const char *connector_name = "Television";
|
||||
|
||||
if (!mdev)
|
||||
@@ -660,17 +689,6 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
|
||||
return ret;
|
||||
|
||||
if (!ntuner) {
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0))
|
||||
if ((ret = media_get_pad_index(tuner, true,
|
||||
PAD_SIGNAL_ANALOG)) < 0)
|
||||
return ret;
|
||||
source_pad = (u16) ret;
|
||||
ret = 0;
|
||||
#else
|
||||
source_pad = TUNER_PAD_RF_INPUT;
|
||||
#endif
|
||||
|
||||
ret = media_create_pad_links(mdev,
|
||||
MEDIA_ENT_F_CONN_RF,
|
||||
conn, 0,
|
||||
@@ -679,32 +697,40 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
|
||||
MEDIA_LNK_FL_ENABLED,
|
||||
false);
|
||||
} else {
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0))
|
||||
pad_sink = media_get_pad_index(tuner, true,
|
||||
PAD_SIGNAL_ANALOG);
|
||||
if (pad_sink < 0)
|
||||
return -EINVAL;
|
||||
ret = media_create_pad_links(mdev,
|
||||
MEDIA_ENT_F_CONN_RF,
|
||||
conn, 0,
|
||||
MEDIA_ENT_F_TUNER,
|
||||
tuner, source_pad,
|
||||
tuner, pad_sink,
|
||||
MEDIA_LNK_FL_ENABLED,
|
||||
false);
|
||||
#else
|
||||
pad_sink = TUNER_PAD_RF_INPUT;
|
||||
#endif
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ntuner && ndemod) {
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0))
|
||||
if ((ret = media_get_pad_index(tuner, true, PAD_SIGNAL_ANALOG)) < 0)
|
||||
return ret;
|
||||
source_pad = (u16) ret;
|
||||
ret = 0;
|
||||
/* NOTE: first found tuner source pad presumed correct */
|
||||
pad_source = media_get_pad_index(tuner, false,
|
||||
PAD_SIGNAL_ANALOG);
|
||||
if (pad_source < 0)
|
||||
return -EINVAL;
|
||||
#else
|
||||
source_pad = TUNER_PAD_OUTPUT;
|
||||
pad_source = TUNER_PAD_OUTPUT;
|
||||
#endif
|
||||
|
||||
ret = media_create_pad_links(mdev,
|
||||
MEDIA_ENT_F_TUNER,
|
||||
tuner, source_pad,
|
||||
tuner, pad_source,
|
||||
MEDIA_ENT_F_DTV_DEMOD,
|
||||
demod, 0, MEDIA_LNK_FL_ENABLED,
|
||||
false);
|
||||
@@ -757,14 +783,16 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
|
||||
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);
|
||||
MEDIA_LNK_FL_ENABLED |
|
||||
MEDIA_LNK_FL_IMMUTABLE);
|
||||
if (!link)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (intf->type == MEDIA_INTF_T_DVB_FE && tuner) {
|
||||
link = media_create_intf_link(tuner, intf,
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
MEDIA_LNK_FL_ENABLED |
|
||||
MEDIA_LNK_FL_IMMUTABLE);
|
||||
if (!link)
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -776,7 +804,8 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
|
||||
*/
|
||||
if (intf->type == MEDIA_INTF_T_DVB_DVR && demux) {
|
||||
link = media_create_intf_link(demux, intf,
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
MEDIA_LNK_FL_ENABLED |
|
||||
MEDIA_LNK_FL_IMMUTABLE);
|
||||
if (!link)
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -862,6 +891,10 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
|
||||
adap->mfe_dvbdev = NULL;
|
||||
mutex_init (&adap->mfe_lock);
|
||||
|
||||
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
|
||||
mutex_init(&adap->mdev_lock);
|
||||
#endif
|
||||
|
||||
list_add_tail (&adap->list_head, &dvb_adapter_list);
|
||||
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
@@ -882,7 +915,7 @@ EXPORT_SYMBOL(dvb_unregister_adapter);
|
||||
|
||||
/* if the miracle happens and "generic_usercopy()" is included into
|
||||
the kernel, then this can vanish. please don't make the mistake and
|
||||
define this as video_usercopy(). this will introduce a dependecy
|
||||
define this as video_usercopy(). this will introduce a dependency
|
||||
to the v4l "videodev.o" module, which is unnecessary for some
|
||||
cards (ie. the budget dvb-cards don't need the v4l module...) */
|
||||
int dvb_usercopy(struct file *file,
|
||||
@@ -946,6 +979,57 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_usercopy);
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0))
|
||||
struct i2c_client *dvb_module_probe(const char *module_name,
|
||||
const char *name,
|
||||
struct i2c_adapter *adap,
|
||||
unsigned char addr,
|
||||
void *platform_data)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
struct i2c_board_info *board_info;
|
||||
|
||||
board_info = kzalloc(sizeof(*board_info), GFP_KERNEL);
|
||||
if (!board_info)
|
||||
return NULL;
|
||||
|
||||
if (name)
|
||||
strscpy(board_info->type, name, I2C_NAME_SIZE);
|
||||
else
|
||||
strscpy(board_info->type, module_name, I2C_NAME_SIZE);
|
||||
|
||||
board_info->addr = addr;
|
||||
board_info->platform_data = platform_data;
|
||||
request_module(module_name);
|
||||
client = i2c_new_client_device(adap, board_info);
|
||||
if (!i2c_client_has_driver(client)) {
|
||||
kfree(board_info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!try_module_get(client->dev.driver->owner)) {
|
||||
i2c_unregister_device(client);
|
||||
client = NULL;
|
||||
}
|
||||
|
||||
kfree(board_info);
|
||||
return client;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dvb_module_probe);
|
||||
|
||||
void dvb_module_release(struct i2c_client *client)
|
||||
{
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
module_put(client->dev.driver->owner);
|
||||
i2c_unregister_device(client);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dvb_module_release);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
struct dvb_device *dvbdev = dev_get_drvdata(dev);
|
||||
|
@@ -1,322 +0,0 @@
|
||||
/*
|
||||
* dvbdev.h
|
||||
*
|
||||
* Copyright (C) 2000 Ralph Metzler & Marcus Metzler
|
||||
* for convergence integrated media GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Lesser Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DVBDEV_H_
|
||||
#define _DVBDEV_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/list.h>
|
||||
#include <media/media-device.h>
|
||||
|
||||
#define DVB_MAJOR 212
|
||||
|
||||
#if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0
|
||||
#define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS
|
||||
#else
|
||||
#define DVB_MAX_ADAPTERS 64
|
||||
#endif
|
||||
|
||||
#define DVB_UNSET (-1)
|
||||
|
||||
#define DVB_DEVICE_VIDEO 0
|
||||
#define DVB_DEVICE_AUDIO 1
|
||||
#define DVB_DEVICE_SEC 2
|
||||
#define DVB_DEVICE_FRONTEND 3
|
||||
#define DVB_DEVICE_DEMUX 4
|
||||
#define DVB_DEVICE_DVR 5
|
||||
#define DVB_DEVICE_CA 6
|
||||
#define DVB_DEVICE_NET 7
|
||||
#define DVB_DEVICE_OSD 8
|
||||
#define DVB_DEVICE_CI 9
|
||||
#define DVB_DEVICE_MOD 10
|
||||
#define DVB_DEVICE_NS 11
|
||||
#define DVB_DEVICE_NSD 12
|
||||
|
||||
#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \
|
||||
static short adapter_nr[] = \
|
||||
{[0 ... (DVB_MAX_ADAPTERS - 1)] = DVB_UNSET }; \
|
||||
module_param_array(adapter_nr, short, NULL, 0444); \
|
||||
MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers")
|
||||
|
||||
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 {
|
||||
int num;
|
||||
struct list_head list_head;
|
||||
struct list_head device_list;
|
||||
const char *name;
|
||||
u8 proposed_mac [6];
|
||||
void* priv;
|
||||
|
||||
struct device *device;
|
||||
|
||||
struct module *module;
|
||||
|
||||
int mfe_shared; /* indicates mutually exclusive frontends */
|
||||
struct dvb_device *mfe_dvbdev; /* frontend device in use */
|
||||
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 list_head list_head;
|
||||
const struct file_operations *fops;
|
||||
struct dvb_adapter *adapter;
|
||||
int type;
|
||||
int minor;
|
||||
u32 id;
|
||||
|
||||
/* in theory, 'users' can vanish now,
|
||||
but I don't want to change too much now... */
|
||||
int readers;
|
||||
int writers;
|
||||
int users;
|
||||
|
||||
wait_queue_head_t wait_queue;
|
||||
/* don't really need those !? -- FIXME: use video_usercopy */
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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,
|
||||
short *adapter_nums);
|
||||
|
||||
/**
|
||||
* 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,
|
||||
const struct dvb_device *template,
|
||||
void *priv,
|
||||
int type,
|
||||
int demux_sink_pads);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* dvb_free_device - Free memory occupied by a DVB device.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/* we don't mess with video_usercopy() any more,
|
||||
we simply define out own dvb_usercopy(), which will hopefully become
|
||||
generic_usercopy() someday... */
|
||||
|
||||
int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
|
||||
int (*func)(struct file *file, unsigned int cmd, void *arg));
|
||||
|
||||
/** generic DVB attach function. */
|
||||
#ifdef CONFIG_MEDIA_ATTACH
|
||||
#define dvb_attach(FUNCTION, ARGS...) ({ \
|
||||
void *__r = NULL; \
|
||||
typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
|
||||
if (__a) { \
|
||||
__r = (void *) __a(ARGS); \
|
||||
if (__r == NULL) \
|
||||
symbol_put(FUNCTION); \
|
||||
} else { \
|
||||
printk(KERN_ERR "DVB: Unable to find symbol "#FUNCTION"()\n"); \
|
||||
} \
|
||||
__r; \
|
||||
})
|
||||
|
||||
#define dvb_detach(FUNC) symbol_put_addr(FUNC)
|
||||
|
||||
#else
|
||||
#define dvb_attach(FUNCTION, ARGS...) ({ \
|
||||
FUNCTION(ARGS); \
|
||||
})
|
||||
|
||||
#define dvb_detach(FUNC) {}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef _DVBDEV_H_ */
|
Reference in New Issue
Block a user