diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-15 20:30:12 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-15 20:30:12 -0800 |
commit | 5d352e69c60e54b5f04d6e337a1d2bf0dbf3d94a (patch) | |
tree | 214e6b190715267ed02b6d415396c2bbcf2eaace /drivers/media/dvb-core | |
parent | 93ea0eb7d77afab34657715630d692a78b8cea6a (diff) | |
parent | f2ecc3d0787e05d9145722feed01d4a11ab6bec1 (diff) |
Merge tag 'media/v4.15-1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- Documentation for digital TV (both kAPI and uAPI) are now in sync
with the implementation (except for legacy/deprecated ioctls). This
is a major step, as there were always a gap there
- New sensor driver: imx274
- New cec driver: cec-gpio
- New platform driver for rockship rga and tegra CEC
- New RC driver: tango-ir
- Several cleanups at atomisp driver
- Core improvements for RC, CEC, V4L2 async probing support and DVB
- Lots of drivers cleanup, fixes and improvements.
* tag 'media/v4.15-1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (332 commits)
dvb_frontend: don't use-after-free the frontend struct
media: dib0700: fix invalid dvb_detach argument
media: v4l2-ctrls: Don't validate BITMASK twice
media: s5p-mfc: fix lockdep warning
media: dvb-core: always call invoke_release() in fe_free()
media: usb: dvb-usb-v2: dvb_usb_core: remove redundant code in dvb_usb_fe_sleep
media: au0828: make const array addr_list static
media: cx88: make const arrays default_addr_list and pvr2000_addr_list static
media: drxd: make const array fastIncrDecLUT static
media: usb: fix spelling mistake: "synchronuously" -> "synchronously"
media: ddbridge: fix build warnings
media: av7110: avoid 2038 overflow in debug print
media: Don't do DMA on stack for firmware upload in the AS102 driver
media: v4l: async: fix unregister for implicitly registered sub-device notifiers
media: v4l: async: fix return of unitialized variable ret
media: imx274: fix missing return assignment from call to imx274_mode_regs
media: camss-vfe: always initialize reg at vfe_set_xbar_cfg()
media: atomisp: make function calls cleaner
media: atomisp: get rid of storage_class.h
media: atomisp: get rid of wrong stddef.h include
...
Diffstat (limited to 'drivers/media/dvb-core')
-rw-r--r-- | drivers/media/dvb-core/dmxdev.c | 8 | ||||
-rw-r--r-- | drivers/media/dvb-core/dmxdev.h | 90 | ||||
-rw-r--r-- | drivers/media/dvb-core/dvb_demux.c | 17 | ||||
-rw-r--r-- | drivers/media/dvb-core/dvb_demux.h | 248 | ||||
-rw-r--r-- | drivers/media/dvb-core/dvb_frontend.c | 518 | ||||
-rw-r--r-- | drivers/media/dvb-core/dvb_frontend.h | 117 | ||||
-rw-r--r-- | drivers/media/dvb-core/dvb_net.h | 34 | ||||
-rw-r--r-- | drivers/media/dvb-core/dvbdev.c | 32 | ||||
-rw-r--r-- | drivers/media/dvb-core/dvbdev.h | 137 |
9 files changed, 805 insertions, 396 deletions
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 18e4230865be..3ddd44e1ee77 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -329,9 +329,9 @@ static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, return 0; } -static void dvb_dmxdev_filter_timeout(unsigned long data) +static void dvb_dmxdev_filter_timeout(struct timer_list *t) { - struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data; + struct dmxdev_filter *dmxdevfilter = from_timer(dmxdevfilter, t, timer); dmxdevfilter->buffer.error = -ETIMEDOUT; spin_lock_irq(&dmxdevfilter->dev->lock); @@ -346,8 +346,6 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) del_timer(&dmxdevfilter->timer); if (para->timeout) { - dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout; - dmxdevfilter->timer.data = (unsigned long)dmxdevfilter; dmxdevfilter->timer.expires = jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000; add_timer(&dmxdevfilter->timer); @@ -754,7 +752,7 @@ static int dvb_demux_open(struct inode *inode, struct file *file) dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); dmxdevfilter->type = DMXDEV_TYPE_NONE; dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); - init_timer(&dmxdevfilter->timer); + timer_setup(&dmxdevfilter->timer, dvb_dmxdev_filter_timeout, 0); dvbdev->users++; diff --git a/drivers/media/dvb-core/dmxdev.h b/drivers/media/dvb-core/dmxdev.h index 054fd4eb6192..5e795f5f0f41 100644 --- a/drivers/media/dvb-core/dmxdev.h +++ b/drivers/media/dvb-core/dmxdev.h @@ -36,12 +36,33 @@ #include "demux.h" #include "dvb_ringbuffer.h" +/** + * enum dmxdev_type - type of demux filter type. + * + * @DMXDEV_TYPE_NONE: no filter set. + * @DMXDEV_TYPE_SEC: section filter. + * @DMXDEV_TYPE_PES: Program Elementary Stream (PES) filter. + */ enum dmxdev_type { DMXDEV_TYPE_NONE, DMXDEV_TYPE_SEC, DMXDEV_TYPE_PES, }; +/** + * enum dmxdev_state - state machine for the dmxdev. + * + * @DMXDEV_STATE_FREE: indicates that the filter is freed. + * @DMXDEV_STATE_ALLOCATED: indicates that the filter was allocated + * to be used. + * @DMXDEV_STATE_SET: indicates that the filter parameters are set. + * @DMXDEV_STATE_GO: indicates that the filter is running. + * @DMXDEV_STATE_DONE: indicates that a packet was already filtered + * and the filter is now disabled. + * Set only if %DMX_ONESHOT. See + * &dmx_sct_filter_params. + * @DMXDEV_STATE_TIMEDOUT: Indicates a timeout condition. + */ enum dmxdev_state { DMXDEV_STATE_FREE, DMXDEV_STATE_ALLOCATED, @@ -51,12 +72,49 @@ enum dmxdev_state { DMXDEV_STATE_TIMEDOUT }; +/** + * struct dmxdev_feed - digital TV dmxdev feed + * + * @pid: Program ID to be filtered + * @ts: pointer to &struct dmx_ts_feed + * @next: &struct list_head pointing to the next feed. + */ + struct dmxdev_feed { u16 pid; struct dmx_ts_feed *ts; struct list_head next; }; +/** + * struct dmxdev_filter - digital TV dmxdev filter + * + * @filter: a dmxdev filter. Currently used only for section filter: + * if the filter is Section, it contains a + * &struct dmx_section_filter @sec pointer. + * @feed: a dmxdev feed. Depending on the feed type, it can be: + * for TS feed: a &struct list_head @ts list of TS and PES + * feeds; + * for section feed: a &struct dmx_section_feed @sec pointer. + * @params: dmxdev filter parameters. Depending on the feed type, it + * can be: + * for section filter: a &struct dmx_sct_filter_params @sec + * embedded struct; + * for a TS filter: a &struct dmx_pes_filter_params @pes + * embedded struct. + * @type: type of the dmxdev filter, as defined by &enum dmxdev_type. + * @state: state of the dmxdev filter, as defined by &enum dmxdev_state. + * @dev: pointer to &struct dmxdev. + * @buffer: an embedded &struct dvb_ringbuffer buffer. + * @mutex: protects the access to &struct dmxdev_filter. + * @timer: &struct timer_list embedded timer, used to check for + * feed timeouts. + * Only for section filter. + * @todo: index for the @secheader. + * Only for section filter. + * @secheader: buffer cache to parse the section header. + * Only for section filter. + */ struct dmxdev_filter { union { struct dmx_section_filter *sec; @@ -86,7 +144,23 @@ struct dmxdev_filter { u8 secheader[3]; }; - +/** + * struct dmxdev - Describes a digital TV demux device. + * + * @dvbdev: pointer to &struct dvb_device associated with + * the demux device node. + * @dvr_dvbdev: pointer to &struct dvb_device associated with + * the dvr device node. + * @filter: pointer to &struct dmxdev_filter. + * @demux: pointer to &struct dmx_demux. + * @filternum: number of filters. + * @capabilities: demux capabilities as defined by &enum dmx_demux_caps. + * @exit: flag to indicate that the demux is being released. + * @dvr_orig_fe: pointer to &struct dmx_frontend. + * @dvr_buffer: embedded &struct dvb_ringbuffer for DVB output. + * @mutex: protects the usage of this structure. + * @lock: protects access to &dmxdev->filter->data. + */ struct dmxdev { struct dvb_device *dvbdev; struct dvb_device *dvr_dvbdev; @@ -108,8 +182,20 @@ struct dmxdev { spinlock_t lock; }; +/** + * dvb_dmxdev_init - initializes a digital TV demux and registers both demux + * and DVR devices. + * + * @dmxdev: pointer to &struct dmxdev. + * @adap: pointer to &struct dvb_adapter. + */ +int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *adap); -int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *); +/** + * dvb_dmxdev_release - releases a digital TV demux and unregisters it. + * + * @dmxdev: pointer to &struct dmxdev. + */ void dvb_dmxdev_release(struct dmxdev *dmxdev); #endif /* _DMXDEV_H_ */ diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index 6628f80d184f..acade7543b82 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -223,10 +223,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) @@ -318,10 +318,10 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, */ #endif /* - * Discontinuity detected. Reset pusi_seen = 0 to + * Discontinuity detected. Reset pusi_seen to * stop feeding of suspicious data until next PUSI=1 arrives */ - feed->pusi_seen = 0; + feed->pusi_seen = false; dvb_dmx_swfilter_section_new(feed); } @@ -335,8 +335,8 @@ 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); @@ -367,6 +367,7 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, else feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts); } + /* 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); @@ -898,14 +899,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)); } diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index 6f572ca8d339..cc048f09aa85 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -26,15 +26,33 @@ #include "demux.h" -#define DMX_TYPE_TS 0 -#define DMX_TYPE_SEC 1 -#define DMX_TYPE_PES 2 +/** + * enum dvb_dmx_filter_type - type of demux feed. + * + * @DMX_TYPE_TS: feed is in TS mode. + * @DMX_TYPE_SEC: feed is in Section mode. + */ +enum dvb_dmx_filter_type { + DMX_TYPE_TS, + DMX_TYPE_SEC, +}; -#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 +/** + * enum dvb_dmx_state - state machine for a demux filter. + * + * @DMX_STATE_FREE: indicates that the filter is freed. + * @DMX_STATE_ALLOCATED: indicates that the filter was allocated + * to be used. + * @DMX_STATE_READY: indicates that the filter is ready + * to be used. + * @DMX_STATE_GO: indicates that the filter is running. + */ +enum dvb_dmx_state { + DMX_STATE_FREE, + DMX_STATE_ALLOCATED, + DMX_STATE_READY, + DMX_STATE_GO, +}; #define DVB_DEMUX_MASK_MAX 18 @@ -42,24 +60,66 @@ #define SPEED_PKTS_INTERVAL 50000 +/** + * struct dvb_demux_filter - Describes a DVB demux section filter. + * + * @filter: Section filter as defined by &struct dmx_section_filter. + * @maskandmode: logical ``and`` bit mask. + * @maskandnotmode: logical ``and not`` bit mask. + * @doneq: flag that indicates when a filter is ready. + * @next: pointer to the next section filter. + * @feed: &struct dvb_demux_feed pointer. + * @index: index of the used demux filter. + * @state: state of the filter as described by &enum dvb_dmx_state. + * @type: type of the filter as described + * by &enum dvb_dmx_filter_type. + */ + struct dvb_demux_filter { struct dmx_section_filter filter; u8 maskandmode[DMX_MAX_FILTER_SIZE]; u8 maskandnotmode[DMX_MAX_FILTER_SIZE]; - int doneq; + bool doneq; struct dvb_demux_filter *next; struct dvb_demux_feed *feed; int index; - int state; - int type; + enum dvb_dmx_state state; + enum dvb_dmx_filter_type type; + /* private: used only by av7110 */ 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 - describes a DVB field + * + * @feed: a digital TV feed. It can either be a TS or a section feed: + * if the feed is TS, it contains &struct dvb_ts_feed @ts; + * if the feed is section, it contains + * &struct dmx_section_feed @sec. + * @cb: digital TV callbacks. depending on the feed type, it can be: + * if the feed is TS, it contains a dmx_ts_cb() @ts callback; + * if the feed is section, it contains a dmx_section_cb() @sec + * callback. + * + * @demux: pointer to &struct dvb_demux. + * @priv: private data that can optionally be used by a DVB driver. + * @type: type of the filter, as defined by &enum dvb_dmx_filter_type. + * @state: state of the filter as defined by &enum dvb_dmx_state. + * @pid: PID to be filtered. + * @timeout: feed timeout. + * @filter: pointer to &struct dvb_demux_filter. + * @ts_type: type of TS, as defined by &enum ts_filter_type. + * @pes_type: type of PES, as defined by &enum dmx_ts_pes. + * @cc: MPEG-TS packet continuity counter + * @pusi_seen: if true, indicates that a discontinuity was detected. + * it is used to prevent feeding of garbage from previous section. + * @peslen: length of the PES (Packet Elementary Stream). + * @list_head: head for the list of digital TV demux feeds. + * @index: a unique index for each feed. Can be used as hardware + * pid filter index. + */ struct dvb_demux_feed { union { struct dmx_ts_feed ts; @@ -73,25 +133,63 @@ struct dvb_demux_feed { struct dvb_demux *demux; void *priv; - int type; - int state; + enum dvb_dmx_filter_type type; + enum dvb_dmx_state state; u16 pid; ktime_t timeout; struct dvb_demux_filter *filter; - int ts_type; + enum ts_filter_type ts_type; enum dmx_ts_pes pes_type; int cc; - int pusi_seen; /* prevents feeding of garbage from previous section */ + bool pusi_seen; u16 peslen; struct list_head list_head; - unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */ + unsigned int index; }; +/** + * struct dvb_demux - represents a digital TV demux + * @dmx: embedded &struct dmx_demux with demux capabilities + * and callbacks. + * @priv: private data that can optionally be used by + * a DVB driver. + * @filternum: maximum amount of DVB filters. + * @feednum: maximum amount of DVB feeds. + * @start_feed: callback routine to be called in order to start + * a DVB feed. + * @stop_feed: callback routine to be called in order to stop + * a DVB feed. + * @write_to_decoder: callback routine to be called if the feed is TS and + * it is routed to an A/V decoder, when a new TS packet + * is received. + * Used only on av7110-av.c. + * @check_crc32: callback routine to check CRC. If not initialized, + * dvb_demux will use an internal one. + * @memcopy: callback routine to memcopy received data. + * If not initialized, dvb_demux will default to memcpy(). + * @users: counter for the number of demux opened file descriptors. + * Currently, it is limited to 10 users. + * @filter: pointer to &struct dvb_demux_filter. + * @feed: pointer to &struct dvb_demux_feed. + * @frontend_list: &struct list_head with frontends used by the demux. + * @pesfilter: array of &struct dvb_demux_feed with the PES types + * that will be filtered. + * @pids: list of filtered program IDs. + * @feed_list: &struct list_head with feeds. + * @tsbuf: temporary buffer used internally to store TS packets. + * @tsbufp: temporary buffer index used internally. + * @mutex: pointer to &struct mutex used to protect feed set + * logic. + * @lock: pointer to &spinlock_t, used to protect buffer handling. + * @cnt_storage: buffer used for TS/TEI continuity check. + * @speed_last_time: &ktime_t used for TS speed check. + * @speed_pkts_cnt: packets count used for TS speed check. + */ struct dvb_demux { struct dmx_demux dmx; void *priv; @@ -115,8 +213,6 @@ struct dvb_demux { 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; @@ -130,15 +226,119 @@ struct dvb_demux { ktime_t speed_last_time; /* for TS speed check */ uint32_t speed_pkts_cnt; /* for TS speed check */ + + /* private: used only on av7110 */ + int playing; + int recording; }; -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, +/** + * dvb_dmx_init - initialize a digital TV demux struct. + * + * @demux: &struct dvb_demux to be initialized. + * + * Before being able to register a digital TV demux struct, drivers + * should call this routine. On its typical usage, some fields should + * be initialized at the driver before calling it. + * + * A typical usecase is:: + * + * dvb->demux.dmx.capabilities = + * DMX_TS_FILTERING | DMX_SECTION_FILTERING | + * DMX_MEMORY_BASED_FILTERING; + * dvb->demux.priv = dvb; + * dvb->demux.filternum = 256; + * dvb->demux.feednum = 256; + * dvb->demux.start_feed = driver_start_feed; + * dvb->demux.stop_feed = driver_stop_feed; + * ret = dvb_dmx_init(&dvb->demux); + * if (ret < 0) + * return ret; + */ +int dvb_dmx_init(struct dvb_demux *demux); + +/** + * dvb_dmx_release - releases a digital TV demux internal buffers. + * + * @demux: &struct dvb_demux to be released. + * + * The DVB core internally allocates data at @demux. This routine + * releases those data. Please notice that the struct itelf is not + * released, as it can be embedded on other structs. + */ +void dvb_dmx_release(struct dvb_demux *demux); + +/** + * dvb_dmx_swfilter_packets - use dvb software filter for a buffer with + * multiple MPEG-TS packets with 188 bytes each. + * + * @demux: pointer to &struct dvb_demux + * @buf: buffer with data to be filtered + * @count: number of MPEG-TS packets with size of 188. + * + * The routine will discard a DVB packet that don't start with 0x47. + * + * Use this routine if the DVB demux fills MPEG-TS buffers that are + * already aligned. + * + * NOTE: The @buf size should have size equal to ``count * 188``. + */ +void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t count); + +/** + * dvb_dmx_swfilter - use dvb software filter for a buffer with + * multiple MPEG-TS packets with 188 bytes each. + * + * @demux: pointer to &struct dvb_demux + * @buf: buffer with data to be filtered + * @count: number of MPEG-TS packets with size of 188. + * + * If a DVB packet doesn't start with 0x47, it will seek for the first + * byte that starts with 0x47. + * + * Use this routine if the DVB demux fill buffers that may not start with + * a packet start mark (0x47). + * + * NOTE: The @buf size should have size equal to ``count * 188``. + */ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count); + +/** + * dvb_dmx_swfilter_204 - use dvb software filter for a buffer with + * multiple MPEG-TS packets with 204 bytes each. + * + * @demux: pointer to &struct dvb_demux + * @buf: buffer with data to be filtered + * @count: number of MPEG-TS packets with size of 204. + * + * If a DVB packet doesn't start with 0x47, it will seek for the first + * byte that starts with 0x47. + * + * Use this routine if the DVB demux fill buffers that may not start with + * a packet start mark (0x47). + * + * NOTE: The @buf size should have size equal to ``count * 204``. + */ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count); + +/** + * dvb_dmx_swfilter_raw - make the raw data available to userspace without + * filtering + * + * @demux: pointer to &struct dvb_demux + * @buf: buffer with data + * @count: number of packets to be passed. The actual size of each packet + * depends on the &dvb_demux->feed->cb.ts logic. + * + * Use it if the driver needs to deliver the raw payload to userspace without + * passing through the kernel demux. That is meant to support some + * delivery systems that aren't based on MPEG-TS. + * + * This function relies on &dvb_demux->feed->cb.ts to actually handle the + * buffer. + */ void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count); diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 9139d01ba7ed..3ad83359098b 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -145,15 +145,13 @@ static void __dvb_frontend_free(struct dvb_frontend *fe) { struct dvb_frontend_private *fepriv = fe->frontend_priv; - if (!fepriv) - return; - - dvb_free_device(fepriv->dvbdev); + if (fepriv) + dvb_free_device(fepriv->dvbdev); dvb_frontend_invoke_release(fe, fe->ops.release); - kfree(fepriv); - fe->frontend_priv = NULL; + if (fepriv) + kfree(fepriv); } static void dvb_frontend_free(struct kref *ref) @@ -951,8 +949,6 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) memset(c, 0, offsetof(struct dtv_frontend_properties, strength)); c->delivery_system = delsys; - c->state = DTV_CLEAR; - dev_dbg(fe->dvb->device, "%s: Clearing cache for delivery system %d\n", __func__, c->delivery_system); @@ -1109,39 +1105,6 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0), }; -static void dtv_property_dump(struct dvb_frontend *fe, - bool is_set, - struct dtv_property *tvp) -{ - int i; - - if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) { - dev_warn(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x undefined\n", - __func__, - is_set ? "SET" : "GET", - tvp->cmd); - return; - } - - dev_dbg(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x (%s)\n", __func__, - is_set ? "SET" : "GET", - tvp->cmd, - dtv_cmds[tvp->cmd].name); - - if (dtv_cmds[tvp->cmd].buffer) { - dev_dbg(fe->dvb->device, "%s: tvp.u.buffer.len = 0x%02x\n", - __func__, tvp->u.buffer.len); - - for(i = 0; i < tvp->u.buffer.len; i++) - dev_dbg(fe->dvb->device, - "%s: tvp.u.buffer.data[0x%02x] = 0x%02x\n", - __func__, i, tvp->u.buffer.data[i]); - } else { - dev_dbg(fe->dvb->device, "%s: tvp.u.data = 0x%08x\n", __func__, - tvp->u.data); - } -} - /* Synchronise the legacy tuning parameters into the cache, so that demodulator * drivers can use a single set_frontend tuning function, regardless of whether * it's being used for the legacy or new API, reducing code and complexity. @@ -1315,17 +1278,15 @@ static int dtv_get_frontend(struct dvb_frontend *fe, return 0; } -static int dvb_frontend_ioctl_legacy(struct file *file, - unsigned int cmd, void *parg); -static int dvb_frontend_ioctl_properties(struct file *file, - unsigned int cmd, void *parg); +static int dvb_frontend_handle_ioctl(struct file *file, + unsigned int cmd, void *parg); static int dtv_property_process_get(struct dvb_frontend *fe, const struct dtv_frontend_properties *c, struct dtv_property *tvp, struct file *file) { - int r, ncaps; + int ncaps; switch(tvp->cmd) { case DTV_ENUM_DELSYS: @@ -1536,14 +1497,18 @@ static int dtv_property_process_get(struct dvb_frontend *fe, return -EINVAL; } - /* Allow the frontend to override outgoing properties */ - if (fe->ops.get_property) { - r = fe->ops.get_property(fe, tvp); - if (r < 0) - return r; - } - - dtv_property_dump(fe, false, tvp); + if (!dtv_cmds[tvp->cmd].buffer) + dev_dbg(fe->dvb->device, + "%s: GET cmd 0x%08x (%s) = 0x%08x\n", + __func__, tvp->cmd, dtv_cmds[tvp->cmd].name, + tvp->u.data); + else + dev_dbg(fe->dvb->device, + "%s: GET cmd 0x%08x (%s) len %d: %*ph\n", + __func__, + tvp->cmd, dtv_cmds[tvp->cmd].name, + tvp->u.buffer.len, + tvp->u.buffer.len, tvp->u.buffer.data); return 0; } @@ -1766,23 +1731,36 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe) return emulate_delivery_system(fe, delsys); } +/** + * dtv_property_process_set - Sets a single DTV property + * @fe: Pointer to &struct dvb_frontend + * @file: Pointer to &struct file + * @cmd: Digital TV command + * @data: An unsigned 32-bits number + * + * This routine assigns the property + * value to the corresponding member of + * &struct dtv_frontend_properties + * + * Returns: + * Zero on success, negative errno on failure. + */ static int dtv_property_process_set(struct dvb_frontend *fe, - struct dtv_property *tvp, - struct file *file) + struct file *file, + u32 cmd, u32 data) { int r = 0; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - /* Allow the frontend to validate incoming properties */ - if (fe->ops.set_property) { - r = fe->ops.set_property(fe, tvp); - if (r < 0) - return r; - } - - dtv_property_dump(fe, true, tvp); - - switch(tvp->cmd) { + /** Dump DTV command name and value*/ + if (!cmd || cmd > DTV_MAX_COMMAND) + dev_warn(fe->dvb->device, "%s: SET cmd 0x%08x undefined\n", + __func__, cmd); + else + dev_dbg(fe->dvb->device, + "%s: SET cmd 0x%08x (%s) to 0x%08x\n", + __func__, cmd, dtv_cmds[cmd].name, data); + switch (cmd) { case DTV_CLEAR: /* * Reset a cache of data specific to the frontend here. This does @@ -1791,144 +1769,144 @@ static int dtv_property_process_set(struct dvb_frontend *fe, dvb_frontend_clear_cache(fe); break; case DTV_TUNE: - /* interpret the cache of data, build either a traditional frontend - * tunerequest so we can pass validation in the FE_SET_FRONTEND - * ioctl. + /* + * Use the cached Digital TV properties to tune the + * frontend */ - c->state = tvp->cmd; - dev_dbg(fe->dvb->device, "%s: Finalised property cache\n", - __func__); + dev_dbg(fe->dvb->device, + "%s: Setting the frontend from property cache\n", + __func__); r = dtv_set_frontend(fe); break; case DTV_FREQUENCY: - c->frequency = tvp->u.data; + c->frequency = data; break; case DTV_MODULATION: - c->modulation = tvp->u.data; + c->modulation = data; break; case DTV_BANDWIDTH_HZ: - c->bandwidth_hz = tvp->u.data; + c->bandwidth_hz = data; break; case DTV_INVERSION: - c->inversion = tvp->u.data; + c->inversion = data; break; case DTV_SYMBOL_RATE: - c->symbol_rate = tvp->u.data; + c->symbol_rate = data; break; case DTV_INNER_FEC: - c->fec_inner = tvp->u.data; + c->fec_inner = data; break; case DTV_PILOT: - c->pilot = tvp->u.data; + c->pilot = data; break; case DTV_ROLLOFF: - c->rolloff = tvp->u.data; + c->rolloff = data; break; case DTV_DELIVERY_SYSTEM: - r = dvbv5_set_delivery_system(fe, tvp->u.data); + r = dvbv5_set_delivery_system(fe, data); break; case DTV_VOLTAGE: - c->voltage = tvp->u.data; - r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE, + c->voltage = data; + r = dvb_frontend_handle_ioctl(file, FE_SET_VOLTAGE, (void *)c->voltage); break; case DTV_TONE: - c->sectone = tvp->u.data; - r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE, + c->sectone = data; + r = dvb_frontend_handle_ioctl(file, FE_SET_TONE, (void *)c->sectone); break; case DTV_CODE_RATE_HP: - c->code_rate_HP = tvp->u.data; + c->code_rate_HP = data; break; case DTV_CODE_RATE_LP: - c->code_rate_LP = tvp->u.data; + c->code_rate_LP = data; break; case DTV_GUARD_INTERVAL: - c->guard_interval = tvp->u.data; + c->guard_interval = data; break; case DTV_TRANSMISSION_MODE: - c->transmission_mode = tvp->u.data; + c->transmission_mode = data; break; case DTV_HIERARCHY: - c->hierarchy = tvp->u.data; + c->hierarchy = data; break; case DTV_INTERLEAVING: - c->interleaving = tvp->u.data; + c->interleaving = data; break; /* ISDB-T Support here */ case DTV_ISDBT_PARTIAL_RECEPTION: - c->isdbt_partial_reception = tvp->u.data; + c->isdbt_partial_reception = data; break; case DTV_ISDBT_SOUND_BROADCASTING: - c->isdbt_sb_mode = tvp->u.data; + c->isdbt_sb_mode = data; break; case DTV_ISDBT_SB_SUBCHANNEL_ID: - c->isdbt_sb_subchannel = tvp->u.data; + c->isdbt_sb_subchannel = data; break; case DTV_ISDBT_SB_SEGMENT_IDX: - c->isdbt_sb_segment_idx = tvp->u.data; + c->isdbt_sb_segment_idx = data; break; case DTV_ISDBT_SB_SEGMENT_COUNT: - c->isdbt_sb_segment_count = tvp->u.data; + c->isdbt_sb_segment_count = data; break; case DTV_ISDBT_LAYER_ENABLED: - c->isdbt_layer_enabled = tvp->u.data; + c->isdbt_layer_enabled = data; break; case DTV_ISDBT_LAYERA_FEC: - c->layer[0].fec = tvp->u.data; + c->layer[0].fec = data; break; case DTV_ISDBT_LAYERA_MODULATION: - c->layer[0].modulation = tvp->u.data; + c->layer[0].modulation = data; break; case DTV_ISDBT_LAYERA_SEGMENT_COUNT: - c->layer[0].segment_count = tvp->u.data; + c->layer[0].segment_count = data; break; case DTV_ISDBT_LAYERA_TIME_INTERLEAVING: - c->layer[0].interleaving = tvp->u.data; + c->layer[0].interleaving = data; break; case DTV_ISDBT_LAYERB_FEC: - c->layer[1].fec = tvp->u.data; + c->layer[1].fec = data; break; case DTV_ISDBT_LAYERB_MODULATION: - c->layer[1].modulation = tvp->u.data; + c->layer[1].modulation = data; break; case DTV_ISDBT_LAYERB_SEGMENT_COUNT: - c->layer[1].segment_count = tvp->u.data; + c->layer[1].segment_count = data; break; case DTV_ISDBT_LAYERB_TIME_INTERLEAVING: - c->layer[1].interleaving = tvp->u.data; + c->layer[1].interleaving = data; break; case DTV_ISDBT_LAYERC_FEC: - c->layer[2].fec = tvp->u.data; + c->layer[2].fec = data; break; case DTV_ISDBT_LAYERC_MODULATION: - c->layer[2].modulation = tvp->u.data; + c->layer[2].modulation = data; break; case DTV_ISDBT_LAYERC_SEGMENT_COUNT: - c->layer[2].segment_count = tvp->u.data; + c->layer[2].segment_count = data; break; case DTV_ISDBT_LAYERC_TIME_INTERLEAVING: - c->layer[2].interleaving = tvp->u.data; + c->layer[2].interleaving = data; break; /* Multistream support */ case DTV_STREAM_ID: case DTV_DVBT2_PLP_ID_LEGACY: - c->stream_id = tvp->u.data; + c->stream_id = data; break; /* ATSC-MH */ case DTV_ATSCMH_PARADE_ID: - fe->dtv_property_cache.atscmh_parade_id = tvp->u.data; + fe->dtv_property_cache.atscmh_parade_id = data; break; case DTV_ATSCMH_RS_FRAME_ENSEMBLE: - fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data; + fe->dtv_property_cache.atscmh_rs_frame_ensemble = data; break; case DTV_LNA: - c->lna = tvp->u.data; + c->lna = data; if (fe->ops.set_lna) r = fe->ops.set_lna(fe); if (r < 0) @@ -1942,14 +1920,12 @@ static int dtv_property_process_set(struct dvb_frontend *fe, return r; } -static int dvb_frontend_ioctl(struct file *file, - unsigned int cmd, void *parg) +static int dvb_frontend_ioctl(struct file *file, unsigned int cmd, void *parg) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_frontend_private *fepriv = fe->frontend_priv; - int err = -EOPNOTSUPP; + int err; dev_dbg(fe->dvb->device, "%s: (%d)\n", __func__, _IOC_NR(cmd)); if (down_interruptible(&fepriv->sem)) @@ -1960,109 +1936,33 @@ static int dvb_frontend_ioctl(struct file *file, return -ENODEV; } - if ((file->f_flags & O_ACCMODE) == O_RDONLY && - (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT || - cmd == FE_DISEQC_RECV_SLAVE_REPLY)) { + /* + * If the frontend is opened in read-only mode, only the ioctls + * that don't interfere with the tune logic should be accepted. + * That allows an external application to monitor the DVB QoS and + * statistics parameters. + * + * That matches all _IOR() ioctls, except for two special cases: + * - FE_GET_EVENT is part of the tuning logic on a DVB application; + * - FE_DISEQC_RECV_SLAVE_REPLY is part of DiSEqC 2.0 + * setup + * So, those two ioctls should also return -EPERM, as otherwise + * reading from them would interfere with a DVB tune application + */ + if ((file->f_flags & O_ACCMODE) == O_RDONLY + && (_IOC_DIR(cmd) != _IOC_READ + || cmd == FE_GET_EVENT + || cmd == FE_DISEQC_RECV_SLAVE_REPLY)) { up(&fepriv->sem); return -EPERM; } - if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY)) - err = dvb_frontend_ioctl_properties(file, cmd, parg); - else { - c->state = DTV_UNDEFINED; - err = dvb_frontend_ioctl_legacy(file, cmd, parg); - } + err = dvb_frontend_handle_ioctl(file, cmd, parg); up(&fepriv->sem); return err; } -static int dvb_frontend_ioctl_properties(struct file *file, - unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_frontend *fe = dvbdev->priv; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int err = 0; - - struct dtv_properties *tvps = parg; - struct dtv_property *tvp = NULL; - int i; - - dev_dbg(fe->dvb->device, "%s:\n", __func__); - - if (cmd == FE_SET_PROPERTY) { - dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num); - dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props); - - /* Put an arbitrary limit on the number of messages that can - * be sent at once */ - if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) - return -EINVAL; - - tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); - if (IS_ERR(tvp)) - return PTR_ERR(tvp); - - for (i = 0; i < tvps->num; i++) { - err = dtv_property_process_set(fe, tvp + i, file); - if (err < 0) - goto out; - (tvp + i)->result = err; - } - - if (c->state == DTV_TUNE) - dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__); - - } else if (cmd == FE_GET_PROPERTY) { - struct dtv_frontend_properties getp = fe->dtv_property_cache; - - dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num); - dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props); - - /* Put an arbitrary limit on the number of messages that can - * be sent at once */ - if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) - return -EINVAL; - - tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); - if (IS_ERR(tvp)) - return PTR_ERR(tvp); - - /* - * Let's use our own copy of property cache, in order to - * avoid mangling with DTV zigzag logic, as drivers might - * return crap, if they don't check if the data is available - * before updating the properties cache. - */ - if (fepriv->state != FESTATE_IDLE) { - err = dtv_get_frontend(fe, &getp, NULL); - if (err < 0) - goto out; - } - for (i = 0; i < tvps->num; i++) { - err = dtv_property_process_get(fe, &getp, tvp + i, file); - if (err < 0) - goto out; - (tvp + i)->result = err; - } - - if (copy_to_user((void __user *)tvps->props, tvp, - tvps->num * sizeof(struct dtv_property))) { - err = -EFAULT; - goto out; - } - - } else - err = -EOPNOTSUPP; - -out: - kfree(tvp); - return err; -} - static int dtv_set_frontend(struct dvb_frontend *fe) { struct dvb_frontend_private *fepriv = fe->frontend_priv; @@ -2200,16 +2100,102 @@ static int dtv_set_frontend(struct dvb_frontend *fe) } -static int dvb_frontend_ioctl_legacy(struct file *file, - unsigned int cmd, void *parg) +static int dvb_frontend_handle_ioctl(struct file *file, + unsigned int cmd, void *parg) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int err = -EOPNOTSUPP; + int i, err; + + dev_dbg(fe->dvb->device, "%s:\n", __func__); switch (cmd) { + case FE_SET_PROPERTY: { + struct dtv_properties *tvps = parg; + struct dtv_property *tvp = NULL; + + dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", + __func__, tvps->num); + dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", + __func__, tvps->props); + + /* + * Put an arbitrary limit on the number of messages that can + * be sent at once + */ + if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) + return -EINVAL; + + tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); + if (IS_ERR(tvp)) + return PTR_ERR(tvp); + + for (i = 0; i < tvps->num; i++) { + err = dtv_property_process_set(fe, file, + (tvp + i)->cmd, + (tvp + i)->u.data); + if (err < 0) { + kfree(tvp); + return err; + } + } + kfree(tvp); + break; + } + case FE_GET_PROPERTY: { + struct dtv_properties *tvps = parg; + struct dtv_property *tvp = NULL; + struct dtv_frontend_properties getp = fe->dtv_property_cache; + + dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", + __func__, tvps->num); + dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", + __func__, tvps->props); + + /* + * Put an arbitrary limit on the number of messages that can + * be sent at once + */ + if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) + return -EINVAL; + + tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); + if (IS_ERR(tvp)) + return PTR_ERR(tvp); + + /* + * Let's use our own copy of property cache, in order to + * avoid mangling with DTV zigzag logic, as drivers might + * return crap, if they don't check if the data is available + * before updating the properties cache. + */ + if (fepriv->state != FESTATE_IDLE) { + err = dtv_get_frontend(fe, &getp, NULL); + if (err < 0) { + kfree(tvp); + return err; + } + } + for (i = 0; i < tvps->num; i++) { + err = dtv_property_process_get(fe, &getp, + tvp + i, file); + if (err < 0) { + kfree(tvp); + return err; + } + } + + if (copy_to_user((void __user *)tvps->props, tvp, + tvps->num * sizeof(struct dtv_property))) { + kfree(tvp); + return -EFAULT; + } + kfree(tvp); + break; + } + case FE_GET_INFO: { struct dvb_frontend_info* info = parg; @@ -2273,42 +2259,6 @@ static int dvb_frontend_ioctl_legacy(struct file *file, break; } - case FE_READ_BER: - if (fe->ops.read_ber) { - if (fepriv->thread) - err = fe->ops.read_ber(fe, (__u32 *) parg); - else - err = -EAGAIN; - } - break; - - case FE_READ_SIGNAL_STRENGTH: - if (fe->ops.read_signal_strength) { - if (fepriv->thread) - err = fe->ops.read_signal_strength(fe, (__u16 *) parg); - else - err = -EAGAIN; - } - break; - - case FE_READ_SNR: - if (fe->ops.read_snr) { - if (fepriv->thread) - err = fe->ops.read_snr(fe, (__u16 *) parg); - else - err = -EAGAIN; - } - break; - - case FE_READ_UNCORRECTED_BLOCKS: - if (fe->ops.read_ucblocks) { - if (fepriv->thread) - err = fe->ops.read_ucblocks(fe, (__u32 *) parg); - else - err = -EAGAIN; - } - break; - case FE_DISEQC_RESET_OVERLOAD: if (fe->ops.diseqc_reset_overload) { err = fe->ops.diseqc_reset_overload(fe); @@ -2360,6 +2310,23 @@ static int dvb_frontend_ioctl_legacy(struct file *file, } break; + case FE_DISEQC_RECV_SLAVE_REPLY: + if (fe->ops.diseqc_recv_slave_reply) + err = fe->ops.diseqc_recv_slave_reply(fe, parg); + break; + + case FE_ENABLE_HIGH_LNB_VOLTAGE: + if (fe->ops.enable_high_lnb_voltage) + err = fe->ops.enable_high_lnb_voltage(fe, (long) parg); + break; + + case FE_SET_FRONTEND_TUNE_MODE: + fepriv->tune_mode_flags = (unsigned long) parg; + err = 0; + break; + + /* DEPRECATED dish control ioctls */ + case FE_DISHNETWORK_SEND_LEGACY_CMD: if (fe->ops.dishnetwork_send_legacy_command) { err = fe->ops.dishnetwork_send_legacy_command(fe, @@ -2425,16 +2392,46 @@ static int dvb_frontend_ioctl_legacy(struct file *file, } break; - case FE_DISEQC_RECV_SLAVE_REPLY: - if (fe->ops.diseqc_recv_slave_reply) - err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg); + /* DEPRECATED statistics ioctls */ + + case FE_READ_BER: + if (fe->ops.read_ber) { + if (fepriv->thread) + err = fe->ops.read_ber(fe, parg); + else + err = -EAGAIN; + } break; - case FE_ENABLE_HIGH_LNB_VOLTAGE: - if (fe->ops.enable_high_lnb_voltage) - err = fe->ops.enable_high_lnb_voltage(fe, (long) parg); + case FE_READ_SIGNAL_STRENGTH: + if (fe->ops.read_signal_strength) { + if (fepriv->thread) + err = fe->ops.read_signal_strength(fe, parg); + else + err = -EAGAIN; + } break; + case FE_READ_SNR: + if (fe->ops.read_snr) { + if (fepriv->thread) + err = fe->ops.read_snr(fe, parg); + else + err = -EAGAIN; + } + break; + + case FE_READ_UNCORRECTED_BLOCKS: + if (fe->ops.read_ucblocks) { + if (fepriv->thread) + err = fe->ops.read_ucblocks(fe, parg); + else + err = -EAGAIN; + } + break; + + /* DEPRECATED DVBv3 ioctls */ + case FE_SET_FRONTEND: err = dvbv3_set_delivery_system(fe); if (err) @@ -2461,11 +2458,10 @@ static int dvb_frontend_ioctl_legacy(struct file *file, err = dtv_get_frontend(fe, &getp, parg); break; } - case FE_SET_FRONTEND_TUNE_MODE: - fepriv->tune_mode_flags = (unsigned long) parg; - err = 0; - break; - } + + default: + return -ENOTSUPP; + } /* switch */ return err; } diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index 907a05bde162..ace0c2fb26c2 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -180,8 +180,8 @@ enum dvbfe_search { /** * 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. + * @info: embedded &struct dvb_tuner_info with tuner properties + * @release: callback function called when frontend is detached. * 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. @@ -191,14 +191,14 @@ enum dvbfe_search { * 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 + * are stored at &struct 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; + * channel on hybrid tuners. It passes @analog_parameters * to the driver. * @set_config: callback function used to send some tuner-specific * parameters. @@ -207,9 +207,9 @@ enum dvbfe_search { * @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 + * @get_rf_strength: returns the RF signal strength. Used mostly to support * analog TV and radio. Digital TV should report, instead, - * via DVBv5 API (@dvb_frontend.dtv_property_cache;). + * via DVBv5 API (&struct 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 @@ -217,7 +217,7 @@ enum dvbfe_search { * @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 + * NOTE: frequencies used on @get_frequency and @set_frequency are in Hz for * terrestrial/cable or kHz for satellite. * */ @@ -283,14 +283,14 @@ 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;. + * &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. + * %TUNER_STATUS_LOCKED and %TUNER_STATUS_STEREO. * @standby: set the tuner to standby mode. - * @release: callback function called when frontend is dettached. + * @release: callback function called when frontend is detached. * drivers should free any allocated memory. * @i2c_gate_ctrl: controls the I2C gate. Newer drivers should use I2C * mux support instead. @@ -321,10 +321,10 @@ struct dtv_frontend_properties; * struct dvb_frontend_ops - Demodulation information and callbacks for * ditialt TV * - * @info: embedded struct dvb_tuner_info with tuner properties + * @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 + * drivers should clean up, but not yet free the &struct * dvb_frontend allocation. * @release: callback function called when frontend is ready to be * freed. @@ -338,57 +338,57 @@ struct dtv_frontend_properties; * 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. + * @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 properties to be used are stored at &struct + * 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 + * &struct 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 + * 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;, + * 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;, + * 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;, + * 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) + * FE_DISEQC_RESET_OVERLOAD() ioctl (only Satellite) * @diseqc_send_master_cmd: callback function to implement the - * FE_DISEQC_SEND_MASTER_CMD ioctl (only Satellite). + * 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) + * FE_DISEQC_RECV_SLAVE_REPLY() ioctl (only Satellite) * @diseqc_send_burst: callback function to implement the - * FE_DISEQC_SEND_BURST ioctl (only Satellite). + * FE_DISEQC_SEND_BURST() ioctl (only Satellite). * @set_tone: callback function to implement the - * FE_SET_TONE ioctl (only Satellite). + * FE_SET_TONE() ioctl (only Satellite). * @set_voltage: callback function to implement the - * FE_SET_VOLTAGE ioctl (only Satellite). + * FE_SET_VOLTAGE() ioctl (only Satellite). * @enable_high_lnb_voltage: callback function to implement the - * FE_ENABLE_HIGH_LNB_VOLTAGE ioctl (only Satellite). + * 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). + * 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 @@ -399,15 +399,10 @@ struct dtv_frontend_properties; * @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. + * @tuner_ops: pointer to &struct dvb_tuner_ops + * @analog_ops: pointer to &struct analog_demod_ops */ struct dvb_frontend_ops { - struct dvb_frontend_info info; u8 delsys[MAX_DELSYS]; @@ -466,9 +461,6 @@ struct dvb_frontend_ops { 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); }; #ifdef __DVB_CORE__ @@ -565,15 +557,15 @@ struct dtv_frontend_properties { enum fe_sec_voltage voltage; enum fe_sec_tone_mode sectone; - enum fe_spectral_inversion inversion; - enum fe_code_rate fec_inner; + 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; + enum fe_hierarchy hierarchy; u32 symbol_rate; - enum fe_code_rate code_rate_HP; - enum fe_code_rate code_rate_LP; + enum fe_code_rate code_rate_HP; + enum fe_code_rate code_rate_LP; enum fe_pilot pilot; enum fe_rolloff rolloff; @@ -628,11 +620,6 @@ struct dtv_frontend_properties { 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 @@ -643,16 +630,16 @@ struct dtv_frontend_properties { /** * struct dvb_frontend - Frontend structure to be used on drivers. * - * @refcount: refcount to keep track of struct dvb_frontend + * @refcount: refcount to keep track of &struct dvb_frontend * references - * @ops: embedded struct dvb_frontend_ops - * @dvb: pointer to struct dvb_adapter + * @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 + * @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 @@ -681,8 +668,8 @@ struct dvb_frontend { /** * dvb_register_frontend() - Registers a DVB frontend at the adapter * - * @dvb: pointer to the dvb adapter - * @fe: pointer to the frontend struct + * @dvb: pointer to &struct dvb_adapter + * @fe: pointer to &struct dvb_frontend * * Allocate and initialize the private data needed by the frontend core to * manage the frontend and calls dvb_register_device() to register a new @@ -695,7 +682,7 @@ int dvb_register_frontend(struct dvb_adapter *dvb, /** * dvb_unregister_frontend() - Unregisters a DVB frontend * - * @fe: pointer to the frontend struct + * @fe: pointer to &struct dvb_frontend * * Stops the frontend kthread, calls dvb_unregister_device() and frees the * private frontend data allocated by dvb_register_frontend(). @@ -709,14 +696,14 @@ int dvb_unregister_frontend(struct dvb_frontend *fe); /** * dvb_frontend_detach() - Detaches and frees frontend specific data * - * @fe: pointer to the frontend struct + * @fe: pointer to &struct dvb_frontend * * 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 + * 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. */ @@ -725,7 +712,7 @@ void dvb_frontend_detach(struct dvb_frontend *fe); /** * dvb_frontend_suspend() - Suspends a Digital TV frontend * - * @fe: pointer to the frontend struct + * @fe: pointer to &struct dvb_frontend * * This function prepares a Digital TV frontend to suspend. * @@ -743,7 +730,7 @@ int dvb_frontend_suspend(struct dvb_frontend *fe); /** * dvb_frontend_resume() - Resumes a Digital TV frontend * - * @fe: pointer to the frontend struct + * @fe: pointer to &struct dvb_frontend * * This function resumes the usual operation of the tuner after resume. * @@ -764,7 +751,7 @@ int dvb_frontend_resume(struct dvb_frontend *fe); /** * dvb_frontend_reinitialise() - forces a reinitialisation at the frontend * - * @fe: pointer to the frontend struct + * @fe: pointer to &struct dvb_frontend * * Calls &dvb_frontend_ops.init\(\) and &dvb_frontend_ops.tuner_ops.init\(\), * and resets SEC tone and voltage (for Satellite systems). @@ -779,16 +766,16 @@ 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 + * @waketime: pointer to &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 + * 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\(\) + * 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 diff --git a/drivers/media/dvb-core/dvb_net.h b/drivers/media/dvb-core/dvb_net.h index e9b18aa03e02..1eae8bad7cc1 100644 --- a/drivers/media/dvb-core/dvb_net.h +++ b/drivers/media/dvb-core/dvb_net.h @@ -30,6 +30,22 @@ #ifdef CONFIG_DVB_NET +/** + * struct dvb_net - describes a DVB network interface + * + * @dvbdev: pointer to &struct dvb_device. + * @device: array of pointers to &struct net_device. + * @state: array of integers to each net device. A value + * different than zero means that the interface is + * in usage. + * @exit: flag to indicate when the device is being removed. + * @demux: pointer to &struct dmx_demux. + * @ioctl_mutex: protect access to this struct. + * + * Currently, the core supports up to %DVB_NET_DEVICES_MAX (10) network + * devices. + */ + struct dvb_net { struct dvb_device *dvbdev; struct net_device *device[DVB_NET_DEVICES_MAX]; @@ -39,8 +55,22 @@ struct dvb_net { struct mutex ioctl_mutex; }; -void dvb_net_release(struct dvb_net *); -int dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *); +/** + * dvb_net_init - nitializes a digital TV network device and registers it. + * + * @adap: pointer to &struct dvb_adapter. + * @dvbnet: pointer to &struct dvb_net. + * @dmxdemux: pointer to &struct dmx_demux. + */ +int dvb_net_init(struct dvb_adapter *adap, struct dvb_net *dvbnet, + struct dmx_demux *dmxdemux); + +/** + * dvb_net_release - releases a digital TV network device and unregisters it. + * + * @dvbnet: pointer to &struct dvb_net. + */ +void dvb_net_release(struct dvb_net *dvbnet); #else diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index 41aad0f99d73..060c60ddfcc3 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -51,8 +51,15 @@ 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" + [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" }; #ifdef CONFIG_DVB_DYNAMIC_MINORS @@ -60,7 +67,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 @@ -426,8 +448,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; diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h index 49189392cf3b..bbc1c20c0529 100644 --- a/drivers/media/dvb-core/dvbdev.h +++ b/drivers/media/dvb-core/dvbdev.h @@ -35,15 +35,37 @@ #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 +/* List of DVB device types */ + +/** + * enum dvb_device_type - type of the Digital TV device + * + * @DVB_DEVICE_SEC: Digital TV standalone Common Interface (CI) + * @DVB_DEVICE_FRONTEND: Digital TV frontend. + * @DVB_DEVICE_DEMUX: Digital TV demux. + * @DVB_DEVICE_DVR: Digital TV digital video record (DVR). + * @DVB_DEVICE_CA: Digital TV Conditional Access (CA). + * @DVB_DEVICE_NET: Digital TV network. + * + * @DVB_DEVICE_VIDEO: Digital TV video decoder. + * Deprecated. Used only on av7110-av. + * @DVB_DEVICE_AUDIO: Digital TV audio decoder. + * Deprecated. Used only on av7110-av. + * @DVB_DEVICE_OSD: Digital TV On Screen Display (OSD). + * Deprecated. Used only on av7110. + */ +enum dvb_device_type { + DVB_DEVICE_SEC, + DVB_DEVICE_FRONTEND, + DVB_DEVICE_DEMUX, + DVB_DEVICE_DVR, + DVB_DEVICE_CA, + DVB_DEVICE_NET, + + DVB_DEVICE_VIDEO, + DVB_DEVICE_AUDIO, + DVB_DEVICE_OSD, +}; #define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \ static short adapter_nr[] = \ @@ -104,8 +126,7 @@ struct dvb_adapter { * @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 + * @type: type of the device, as defined by &enum dvb_device_type. * @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 @@ -135,7 +156,7 @@ struct dvb_device { struct list_head list_head; const struct file_operations *fops; struct dvb_adapter *adapter; - int type; + enum dvb_device_type type; int minor; u32 id; @@ -194,9 +215,7 @@ int dvb_unregister_adapter(struct dvb_adapter *adap); * 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 + * @type: type of the device, as defined by &enum dvb_device_type. * @demux_sink_pads: Number of demux outputs, to be used to create the TS * outputs via the Media Controller. */ @@ -204,7 +223,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, const struct dvb_device *template, void *priv, - int type, + enum dvb_device_type type, int demux_sink_pads); /** @@ -242,7 +261,7 @@ void dvb_unregister_device(struct dvb_device *dvbdev); * dvb_create_media_graph - Creates media graph for the Digital TV part of the * device. * - * @adap: pointer to struct dvb_adapter + * @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 @@ -255,12 +274,23 @@ void dvb_unregister_device(struct dvb_device *dvbdev); __must_check int dvb_create_media_graph(struct dvb_adapter *adap, bool create_rf_connector); +/** + * dvb_register_media_controller - registers a media controller at DVB adapter + * + * @adap: pointer to &struct dvb_adapter + * @mdev: pointer to &struct media_device + */ static inline void dvb_register_media_controller(struct dvb_adapter *adap, struct media_device *mdev) { adap->mdev = mdev; } +/** + * dvb_get_media_controller - gets the associated media controller + * + * @adap: pointer to &struct dvb_adapter + */ static inline struct media_device *dvb_get_media_controller(struct dvb_adapter *adap) { @@ -277,20 +307,71 @@ int dvb_create_media_graph(struct dvb_adapter *adap, #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); +/** + * dvb_generic_open - Digital TV open function, used by DVB devices + * + * @inode: pointer to &struct inode. + * @file: pointer to &struct file. + * + * Checks if a DVB devnode is still valid, and if the permissions are + * OK and increment negative use count. + */ +int dvb_generic_open(struct inode *inode, struct file *file); -/* we don't mess with video_usercopy() any more, -we simply define out own dvb_usercopy(), which will hopefully become -generic_usercopy() someday... */ +/** + * dvb_generic_close - Digital TV close function, used by DVB devices + * + * @inode: pointer to &struct inode. + * @file: pointer to &struct file. + * + * Checks if a DVB devnode is still valid, and if the permissions are + * OK and decrement negative use count. + */ +int dvb_generic_release(struct inode *inode, struct file *file); +/** + * dvb_generic_ioctl - Digital TV close function, used by DVB devices + * + * @file: pointer to &struct file. + * @cmd: Ioctl name. + * @arg: Ioctl argument. + * + * Checks if a DVB devnode and struct dvbdev.kernel_ioctl is still valid. + * If so, calls dvb_usercopy(). + */ +long dvb_generic_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); + +/** + * dvb_usercopy - copies data from/to userspace memory when an ioctl is + * issued. + * + * @file: Pointer to struct &file. + * @cmd: Ioctl name. + * @arg: Ioctl argument. + * @func: function that will actually handle the ioctl + * + * Ancillary function that uses ioctl direction and size to copy from + * userspace. Then, it calls @func, and, if needed, data is copied back + * to userspace. + */ 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 + +/** + * dvb_attach - attaches a DVB frontend into the DVB core. + * + * @FUNCTION: function on a frontend module to be called. + * @ARGS...: @FUNCTION arguments. + * + * This ancillary function loads a frontend module in runtime and runs + * the @FUNCTION function there, with @ARGS. + * As it increments symbol usage cont, at unregister, dvb_detach() + * should be called. + */ #define dvb_attach(FUNCTION, ARGS...) ({ \ void *__r = NULL; \ typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ @@ -304,6 +385,14 @@ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, __r; \ }) +/** + * dvb_detach - detaches a DVB frontend loaded via dvb_attach() + * + * @FUNC: attach function + * + * Decrements usage count for a function previously called via dvb_attach(). + */ + #define dvb_detach(FUNC) symbol_put_addr(FUNC) #else |