android_kernel_xiaomi_sm8350/drivers/media/dvb/firesat/firesat_dvb.c
Stefan Richter 8ae83cdf32 firedtv: cleanups and minor fixes
Combination of the following changes:

Sun, 2 Nov 2008 13:45:00 +0100 (CET)
firedtv: increase FCP frame length for DVB-S2 tune QSPK

    The last three bytes didn't go out to the wire.
    Effect of the fix not yet tested.

Sun, 2 Nov 2008 13:45:00 +0100 (CET)
firedtv: replace mdelay by msleep

    These functions can sleep (and in fact sleep for the duration of a whole
    FCP transaction).  Hence msleep is more appropriate here.

Sun, 2 Nov 2008 13:45:00 +0100 (CET)
firedtv: trivial reorganization in avc_api

    Reduce nesting level by factoring code out of avc_tuner_dsd() into
    helper functions.

Sun, 2 Nov 2008 13:45:00 +0100 (CET)
firedtv: trivial cleanups in avc_api

    Use dev_err(), no CamelCase function names, adjust comment style, put
    #if 0 around unused code and add FIXME comments, standardize on
    lower-case hexadecimal constants, use ALIGN() for some frame length
    calculations, make a local function static...

    The code which writes FCP command frames and reads FCP response frames
    is not yet brought into canonical kernel coding style because this
    involves changes of typedefs (on-the-wire bitfields).

Sun, 2 Nov 2008 13:45:00 +0100 (CET)
firedtv: don't retry oPCR updates endlessly

    In the theoretical case that the target node wasn't handling the lock
    transactions as expected or there was continued interference by other
    initiating nodes, these functions wouldn't return for ages.

Sun, 2 Nov 2008 13:45:00 +0100 (CET)
firedtv: remove bitfield typedefs from cmp, fix for big endian CPUs

    Use macros/ inline functions/ standard byte order accessors to read and
    write oPCR register values (big endian bitfields, on-the-wire data).
    The new code may not be the ultimate optimum, but it doesn't occur in a
    hot path.

    This fixes the CMP code for big endian CPUs.  So far I tested it only on
    a little endian CPU though.

    For now, include <asm/byteorder.h> instead of <linux/byteorder.h>
    because drivers/ieee1394/*.h also include the former.  I will fix this
    in drivers/ieee1394 and firedtv later.

Sun, 2 Nov 2008 13:45:00 +0100 (CET)
firedtv: trivial cleanups in cmp

    Reduce nesting level by means of early exit and goto.
    Remove obsolete includes, use dev_err(), no CamelCase function names...

Sun, 2 Nov 2008 13:45:00 +0100 (CET)
firedtv: trivial cleanups in firesat-ci

    Whitespace, variable names, comment style...

    Also, use dvb_generic_open() and dvb_generic_release() directly as
    our hooks in struct file_operations because firedtv's wrappers merely
    called these generic functions.

Sun, 2 Nov 2008 13:45:00 +0100 (CET)
firedtv: remove CA debug code

    This looks like it is not necessary to have available for endusers who
    cannot patch kernels for bug reporting and tests of fixes.

Sun, 2 Nov 2008 13:45:00 +0100 (CET)
firedtv: remove AV/C debug code

    This looks like it is not necessary to have available for endusers who
    cannot patch kernels for bug reporting and tests of fixes.

Sun, 2 Nov 2008 13:45:00 +0100 (CET)
firedtv: remove various debug code

    Most of this was already commented out.  And that which wasn't is not
    relevant in normal use.

Mon, 29 Sep 2008 19:22:48 +0200 (CEST)
firedtv: register input device as child of a FireWire device

    Instead of one virtual input device which exists for the whole lifetime
    of the driver and receives events from all connected FireDTVs, register
    one input device for each firedtv device.  These input devices will show
    up as children of the respective firedtv devices in the sysfs hierarchy.

    However, the implementation falls short because of a bug in userspace:
    Udev's path_id script gets stuck with 100% CPU utilization, maybe
    because of an assumption about the maximum ieee1394 device hierarchy
    depth.

    To avoid this bug, we use the fw-host device instead of the proper
    unit_directory device as parent of the input device.

    There is hope that the port to the new firewire stack won't be inhibited
    by this userspace bug because there are no fw-host devices there.

Mon, 29 Sep 2008 19:21:52 +0200 (CEST)
firedtv: fix string comparison and a few sparse warnings

    Sparse found a bug:
    	while ((kv_buf + kv_len - 1) == '\0')
    should have been
    	while (kv_buf[kv_len - 1] == '\0')
    We fix it by a better implementation without a temporary copy.

    Also fix sparse warnings of 0 instead of NULL and signedness mismatches.

Mon, 29 Sep 2008 19:21:20 +0200 (CEST)
firedtv: remove unused struct members

    and redefine an int as a bool.

Mon, 29 Sep 2008 19:20:36 +0200 (CEST)
firedtv: fix initialization of dvb_frontend.ops

    There was a NULL pointer reference if no dvb_frontend_info was found.

    Also, don't directly assign struct typed values to struct typed
    variables.  Instead write out assignments to individual strcut members.
    This reduces module size by about 1 kB.

Mon, 29 Sep 2008 19:19:41 +0200 (CEST)
firedtv: remove unused dual subunit code from initialization

    No FireDTVs with more than one subunit exists, hence simplify the
    initialization for the special case of one subunit.  The driver was able
    to check for more than one subunit but was broken for more than two
    subunits.

    While we are at it, add several missing cleanups after failure, and
    include a few dynamically allocated structures diretly into struct
    firesat instead of allocating them separately.

Mon, 29 Sep 2008 19:19:08 +0200 (CEST)
firedtv: add vendor_id and version to driver match table

    Now that nodemgr was enhanced to match against the root directory's
    vendor ID if there isn't one in the unit directory, use this to
    prevent firedtv to be bound to wrong devices by accident.

    Also add the AV/C software version ID to the match flags for
    completeness; specifier ID and software only make sense as a pair.

Mon, 29 Sep 2008 19:18:30 +0200 (CEST)
firedtv: use hpsb_node_read(), _write(), _lock()

    because they are simpler and treat the node generation more correctly.
    While we are at it, clean up and simplify surrounding code.

Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2009-02-24 14:51:28 +01:00

277 lines
6.5 KiB
C

/*
* FireDTV driver (formerly known as FireSAT)
*
* Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
* Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
*
* 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.
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <dvb_demux.h>
#include <dvb_frontend.h>
#include <dvbdev.h>
#include "avc_api.h"
#include "firesat.h"
#include "firesat-ci.h"
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
static struct firesat_channel *firesat_channel_allocate(struct firesat *firesat)
{
struct firesat_channel *c = NULL;
int k;
if (mutex_lock_interruptible(&firesat->demux_mutex))
return NULL;
for (k = 0; k < 16; k++)
if (!firesat->channel[k].active) {
firesat->channel[k].active = true;
c = &firesat->channel[k];
break;
}
mutex_unlock(&firesat->demux_mutex);
return c;
}
static int firesat_channel_collect(struct firesat *firesat, int *pidc, u16 pid[])
{
int k, l = 0;
if (mutex_lock_interruptible(&firesat->demux_mutex))
return -EINTR;
for (k = 0; k < 16; k++)
if (firesat->channel[k].active)
pid[l++] = firesat->channel[k].pid;
mutex_unlock(&firesat->demux_mutex);
*pidc = l;
return 0;
}
static int firesat_channel_release(struct firesat *firesat,
struct firesat_channel *channel)
{
if (mutex_lock_interruptible(&firesat->demux_mutex))
return -EINTR;
channel->active = false;
mutex_unlock(&firesat->demux_mutex);
return 0;
}
int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed)
{
struct firesat *firesat = (struct firesat*)dvbdmxfeed->demux->priv;
struct firesat_channel *channel;
int pidc,k;
u16 pids[16];
switch (dvbdmxfeed->type) {
case DMX_TYPE_TS:
case DMX_TYPE_SEC:
break;
default:
printk(KERN_ERR "%s: invalid type %u\n",
__func__, dvbdmxfeed->type);
return -EINVAL;
}
if (dvbdmxfeed->type == DMX_TYPE_TS) {
switch (dvbdmxfeed->pes_type) {
case DMX_TS_PES_VIDEO:
case DMX_TS_PES_AUDIO:
case DMX_TS_PES_TELETEXT:
case DMX_TS_PES_PCR:
case DMX_TS_PES_OTHER:
//Dirty fix to keep firesat->channel pid-list up to date
for(k=0;k<16;k++){
if (!firesat->channel[k].active)
firesat->channel[k].pid =
dvbdmxfeed->pid;
break;
}
channel = firesat_channel_allocate(firesat);
break;
default:
printk(KERN_ERR "%s: invalid pes type %u\n",
__func__, dvbdmxfeed->pes_type);
return -EINVAL;
}
} else {
channel = firesat_channel_allocate(firesat);
}
if (!channel) {
printk(KERN_ERR "%s: busy!\n", __func__);
return -EBUSY;
}
dvbdmxfeed->priv = channel;
channel->pid = dvbdmxfeed->pid;
if (firesat_channel_collect(firesat, &pidc, pids)) {
firesat_channel_release(firesat, channel);
printk(KERN_ERR "%s: could not collect pids!\n", __func__);
return -EINTR;
}
if (dvbdmxfeed->pid == 8192) {
k = avc_tuner_get_ts(firesat);
if (k) {
firesat_channel_release(firesat, channel);
printk("%s: AVCTuner_GetTS failed with error %d\n",
__func__, k);
return k;
}
} else {
k = avc_tuner_set_pids(firesat, pidc, pids);
if (k) {
firesat_channel_release(firesat, channel);
printk("%s: AVCTuner_SetPIDs failed with error %d\n",
__func__, k);
return k;
}
}
return 0;
}
int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_demux *demux = dvbdmxfeed->demux;
struct firesat *firesat = (struct firesat*)demux->priv;
struct firesat_channel *c = dvbdmxfeed->priv;
int k, l;
u16 pids[16];
if (dvbdmxfeed->type == DMX_TYPE_TS && !((dvbdmxfeed->ts_type & TS_PACKET) &&
(demux->dmx.frontend->source != DMX_MEMORY_FE))) {
if (dvbdmxfeed->ts_type & TS_DECODER) {
if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER ||
!demux->pesfilter[dvbdmxfeed->pes_type])
return -EINVAL;
demux->pids[dvbdmxfeed->pes_type] |= 0x8000;
demux->pesfilter[dvbdmxfeed->pes_type] = NULL;
}
if (!(dvbdmxfeed->ts_type & TS_DECODER &&
dvbdmxfeed->pes_type < DMX_TS_PES_OTHER))
return 0;
}
if (mutex_lock_interruptible(&firesat->demux_mutex))
return -EINTR;
/* list except channel to be removed */
for (k = 0, l = 0; k < 16; k++)
if (firesat->channel[k].active) {
if (&firesat->channel[k] != c)
pids[l++] = firesat->channel[k].pid;
else
firesat->channel[k].active = false;
}
k = avc_tuner_set_pids(firesat, l, pids);
if (!k)
c->active = false;
mutex_unlock(&firesat->demux_mutex);
return k;
}
int firesat_dvbdev_init(struct firesat *firesat, struct device *dev)
{
int err;
err = DVB_REGISTER_ADAPTER(&firesat->adapter,
firedtv_model_names[firesat->type],
THIS_MODULE, dev, adapter_nr);
if (err)
goto fail_log;
/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/
firesat->demux.dmx.capabilities = 0;
firesat->demux.priv = (void *)firesat;
firesat->demux.filternum = 16;
firesat->demux.feednum = 16;
firesat->demux.start_feed = firesat_start_feed;
firesat->demux.stop_feed = firesat_stop_feed;
firesat->demux.write_to_decoder = NULL;
err = dvb_dmx_init(&firesat->demux);
if (err)
goto fail_unreg_adapter;
firesat->dmxdev.filternum = 16;
firesat->dmxdev.demux = &firesat->demux.dmx;
firesat->dmxdev.capabilities = 0;
err = dvb_dmxdev_init(&firesat->dmxdev, &firesat->adapter);
if (err)
goto fail_dmx_release;
firesat->frontend.source = DMX_FRONTEND_0;
err = firesat->demux.dmx.add_frontend(&firesat->demux.dmx,
&firesat->frontend);
if (err)
goto fail_dmxdev_release;
err = firesat->demux.dmx.connect_frontend(&firesat->demux.dmx,
&firesat->frontend);
if (err)
goto fail_rem_frontend;
dvb_net_init(&firesat->adapter, &firesat->dvbnet, &firesat->demux.dmx);
firesat_frontend_init(firesat);
err = dvb_register_frontend(&firesat->adapter, &firesat->fe);
if (err)
goto fail_net_release;
err = firesat_ca_register(firesat);
if (err)
dev_info(dev, "Conditional Access Module not enabled\n");
return 0;
fail_net_release:
dvb_net_release(&firesat->dvbnet);
firesat->demux.dmx.close(&firesat->demux.dmx);
fail_rem_frontend:
firesat->demux.dmx.remove_frontend(&firesat->demux.dmx,
&firesat->frontend);
fail_dmxdev_release:
dvb_dmxdev_release(&firesat->dmxdev);
fail_dmx_release:
dvb_dmx_release(&firesat->demux);
fail_unreg_adapter:
dvb_unregister_adapter(&firesat->adapter);
fail_log:
dev_err(dev, "DVB initialization failed\n");
return err;
}