Commit 15490795 authored by Stefan Richter's avatar Stefan Richter

firedtv: massive refactoring

Combination of the following changes:

Mon, 23 Feb 2009 14:21:10 +0100 (CET)
firedtv: reinstate debug logging option

    Henrik Kurelid tells me that FCP debug logging (which I removed during
    cleanups) is still useful when working on driver issues together with
    end users.  So bring it back in an updated form with only 60% of the
    original code footprint.

    Logging can be enabled with
    # echo -1 > /sys/module/firedtv/parameters/debug

    1 instead of -1 enables only FCP header logging,
    2 instead of -1 enables only hexdumps of the entire FCP frames.
    0 switches logging off again.

Fri, 20 Feb 2009 20:54:27 +0100 (CET)
firedtv: build fix for INPUT=m and DVB_FIREDTV=y

Thu, 19 Feb 2009 20:40:39 +0100
firedtv: use msecs_to_jiffies

    Pointed out by Mauro Carvalho Chehab.

Sun Feb 15 20:50:46 CET 2009
firedtv: some more housekeeping

    Fix an old checkpatch warning and a new compiler warning.

Sun Feb 15 15:33:17 CET 2009
firedtv: rename a file once more

    At the moment, about a third of avc.c is specific to FireDTVs rather
    than generic AV/C code.  Rename it to firedtv-avc.c.

Sun Feb 15 15:33:17 CET 2009
firedtv: dvb demux: more compact channels backing store

    Replace struct firedtv_channel { bool active; int pid; } channel[16];
    by unsigned long channel_active; u16 channel_pid[16];.

Sun Feb 15 15:33:17 CET 2009
firedtv: dvb demux: some simplifications

    c->active was unnecessarily cleared twice.

    Also, by marking the channel inactive before the for loop,
    the loop becomes identical with fdtv_channel_collect().

Sun Feb 15 15:33:17 CET 2009
firedtv: dvb demux: remove a bogus loop

    This loop is unnecessary because
      - only active channel[].pid's will be sent to the device,
      - when a channel is activated, its pid is set to dvbdmxfeed->pid.

    Perhaps the original code was there because it was initially not fully
    covered by the fdtv->demux_mutex.

Sun Feb 15 15:33:17 CET 2009
firedtv: dvb demux: fix mutex protection

    fdtv_start_feed() accessed the channel list unsafely.
    Fully serialize it with itself and fdtv_stop_feed().

Sun Feb 15 15:33:17 CET 2009
firedtv: dvb demux: fix missing braces

    Original code was:
            ...
            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 == 0)
                                    firesat->channel[k].pid =
                                            dvbdmxfeed->pid;
                                    break;
                    }
                    channel = firesat_channel_allocate(firesat);
                    break;
            default:
            ...

    Looks bogus in several respects. For now let's just add braces to the if
    because that seems to be what the author meant.

Sun Feb 15 15:33:17 CET 2009
firedtv: allow build without input subsystem

    !CONFIG_INPUT is very unlikely on systems on which firedtv is of
    interest.  But we can easily support it.

Sun Feb 15 15:33:17 CET 2009
firedtv: replace EXTRA_CFLAGS by ccflags

    The former are deprecated.
    The latter can depend on Kconfig variables.

Sun Feb 15 15:33:17 CET 2009
firedtv: concentrate ieee1394 dependencies

    Move the entire interface with drivers/ieee1394 to firedtv-1394.c.
    Move 1394-independent module initialization code to firedtv-dvb.c.

    This prepares interfacing with drivers/firewire.

Sun Feb 15 15:33:17 CET 2009
firedtv: amend Kconfig menu prompt

Sun Feb 15 15:33:17 CET 2009
firedtv: remove kernel version compatibility macro

Sun Feb 15 15:33:17 CET 2009
firedtv: combine header files

    avc.h and firedtv-*.h are small and currently not shared with other
    drivers, hence concatenate them all into firedtv.h.

Sun Feb 15 15:33:17 CET 2009
firedtv: misc style touch-ups

    Standardize on lower-case hexadecimal constants.  Adjust whitespace.
    Omit unnecessary pointer type casts and an unnecessary list head
    initialization.  Use dev_printk.

Wed Feb 11 21:21:04 CET 2009
firedtv: avc, ci: remove unused constants

Wed Feb 11 21:21:04 CET 2009
firedtv: avc: remove bitfields from read descriptor response operands

    Don't use bitfields in struct types of on-the-wire data.

Wed Feb 11 21:21:04 CET 2009
firedtv: avc: remove bitfields from DSD command operands

    Don't use bitfields in struct types of on-the-wire data.

Wed Feb 11 21:21:04 CET 2009
firedtv: avc: header file cleanup

    Remove unused constants and declarations.
    Move privately used constants into .c files.

Wed Feb 11 21:21:04 CET 2009
firedtv: avc: remove bitfields from FCP frame types

    Don't use bitfields in struct types of on-the-wire data.

    Also move many privately used constants from avc.h to avc.c
    and remove some unused constants.

Sun, 18 Jan 2009 16:30:00 +0100 (CET)
firedtv: avc: fix offset in avc_tuner_get_ts

    The parentheses were wrong.  It didn't matter though because this code
    only writes a 0 into an area which is already initialized to 0.

Sun, 18 Jan 2009 16:30:00 +0100 (CET)
firedtv: avc: reduce stack usage, remove two typedefs

    It is safe to share a memory buffer for command frame and response frame
    because the response data come in after the command frame was last used.

    Even less stack would be required if only the actual required frame size
    instead of the entire FCP register size was allocated.

    Also, rename the defined types AVCCmdFrm and AVCRspFrm to
    struct avc_command_frame and struct avc_response_frame.
    TODO:  Remove the bitfields in these types.

Sun, 18 Jan 2009 16:30:00 +0100 (CET)
firedtv: cmp: move code to avc

Sun, 18 Jan 2009 16:30:00 +0100 (CET)
firedtv: iso: move code to firedtv-1394

Sun, 18 Jan 2009 16:30:00 +0100 (CET)
firedtv: iso: remove unnecessary struct type definitions

Sun, 18 Jan 2009 16:30:00 +0100 (CET)
firedtv: iso: style changes and fixlets

    Add cleanup after failure in setup_iso_channel.
    Replace printk() by dv_err().
    Decrease indentation level in rawiso_activity_cb().
Signed-off-by: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
parent a70f81c1
......@@ -51,6 +51,8 @@ comment "Supported SDMC DM1105 Adapters"
depends on DVB_CORE && PCI && I2C
source "drivers/media/dvb/dm1105/Kconfig"
comment "Supported FireWire (IEEE 1394) Adapters"
depends on DVB_CORE && IEEE1394
source "drivers/media/dvb/firewire/Kconfig"
comment "Supported DVB Frontends"
......
config DVB_FIREDTV
tristate "FireDTV (FireWire attached DVB receivers)"
depends on DVB_CORE && IEEE1394 && INPUT
tristate "FireDTV and FloppyDTV"
depends on DVB_CORE && IEEE1394
help
Support for DVB receivers from Digital Everywhere, known as FireDTV
and FloppyDTV, which are connected via IEEE 1394 (FireWire).
Support for DVB receivers from Digital Everywhere
which are connected via IEEE 1394 (FireWire).
These devices don't have an MPEG decoder built in, so you need
an external software decoder to watch TV.
These devices don't have an MPEG decoder built in,
so you need an external software decoder to watch TV.
To compile this driver as a module, say M here: the module will be
called firedtv.
To compile this driver as a module, say M here:
the module will be called firedtv.
if DVB_FIREDTV
config DVB_FIREDTV_IEEE1394
def_bool IEEE1394
config DVB_FIREDTV_INPUT
def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m)
endif # DVB_FIREDTV
firedtv-objs := firedtv-1394.o \
firedtv-dvb.o \
firedtv-fe.o \
firedtv-iso.o \
avc.o \
cmp.o \
firedtv-rc.o \
firedtv-ci.o
obj-$(CONFIG_DVB_FIREDTV) += firedtv.o
EXTRA_CFLAGS := -Idrivers/ieee1394
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o
firedtv-$(CONFIG_DVB_FIREDTV_IEEE1394) += firedtv-1394.o
firedtv-$(CONFIG_DVB_FIREDTV_INPUT) += firedtv-rc.o
ccflags-y += -Idrivers/media/dvb/dvb-core
ccflags-$(CONFIG_DVB_FIREDTV_IEEE1394) += -Idrivers/ieee1394
This diff is collapsed.
/*
* AV/C API
*
* Copyright (C) 2000 Manfred Weihs
* Copyright (C) 2003 Philipp Gutgsell <0014guph@edu.fh-kaernten.ac.at>
* Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
* Copyright (C) 2008 Ben Backx <ben@bbackx.com>
* Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
*
* This is based on code written by Peter Halwachs, Thomas Groiss and
* Andreas Monitzer.
*
* 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.
*/
#ifndef _AVC_API_H
#define _AVC_API_H
#include <linux/types.h>
/*************************************************************
Constants from EN510221
**************************************************************/
#define LIST_MANAGEMENT_ONLY 0x03
/************************************************************
definition of structures
*************************************************************/
typedef struct {
int Nr_SourcePlugs;
int Nr_DestinationPlugs;
} TunerInfo;
/***********************************************
supported cts
************************************************/
#define AVC 0x0
// FCP command frame with ctype = 0x0 is AVC command frame
#ifdef __LITTLE_ENDIAN
// Definition FCP Command Frame
typedef struct _AVCCmdFrm
{
// AV/C command frame
__u8 ctype : 4 ; // command type
__u8 cts : 4 ; // always 0x0 for AVC
__u8 suid : 3 ; // subunit ID
__u8 sutyp : 5 ; // subunit_typ
__u8 opcode : 8 ; // opcode
__u8 operand[509] ; // array of operands [1-507]
int length; //length of the command frame
} AVCCmdFrm ;
// Definition FCP Response Frame
typedef struct _AVCRspFrm
{
// AV/C response frame
__u8 resp : 4 ; // response type
__u8 cts : 4 ; // always 0x0 for AVC
__u8 suid : 3 ; // subunit ID
__u8 sutyp : 5 ; // subunit_typ
__u8 opcode : 8 ; // opcode
__u8 operand[509] ; // array of operands [1-507]
int length; //length of the response frame
} AVCRspFrm ;
#else
typedef struct _AVCCmdFrm
{
__u8 cts:4;
__u8 ctype:4;
__u8 sutyp:5;
__u8 suid:3;
__u8 opcode;
__u8 operand[509];
int length;
} AVCCmdFrm;
typedef struct _AVCRspFrm
{
__u8 cts:4;
__u8 resp:4;
__u8 sutyp:5;
__u8 suid:3;
__u8 opcode;
__u8 operand[509];
int length;
} AVCRspFrm;
#endif
/*************************************************************
AVC command types (ctype)
**************************************************************///
#define CONTROL 0x00
#define STATUS 0x01
#define INQUIRY 0x02
#define NOTIFY 0x03
/*************************************************************
AVC respond types
**************************************************************///
#define NOT_IMPLEMENTED 0x8
#define ACCEPTED 0x9
#define REJECTED 0xA
#define STABLE 0xC
#define CHANGED 0xD
#define INTERIM 0xF
/*************************************************************
AVC opcodes
**************************************************************///
#define CONNECT 0x24
#define DISCONNECT 0x25
#define UNIT_INFO 0x30
#define SUBUNIT_Info 0x31
#define VENDOR 0x00
#define PLUG_INFO 0x02
#define OPEN_DESCRIPTOR 0x08
#define READ_DESCRIPTOR 0x09
#define OBJECT_NUMBER_SELECT 0x0D
/*************************************************************
AVCTuner opcodes
**************************************************************/
#define DSIT 0xC8
#define DSD 0xCB
#define DESCRIPTOR_TUNER_STATUS 0x80
#define DESCRIPTOR_SUBUNIT_IDENTIFIER 0x00
/*************************************************************
AVCTuner list types
**************************************************************/
#define Multiplex_List 0x80
#define Service_List 0x82
/*************************************************************
AVCTuner object entries
**************************************************************/
#define Multiplex 0x80
#define Service 0x82
#define Service_with_specified_components 0x83
#define Preferred_components 0x90
#define Component 0x84
/*************************************************************
Vendor-specific commands
**************************************************************/
// digital everywhere vendor ID
#define SFE_VENDOR_DE_COMPANYID_0 0x00
#define SFE_VENDOR_DE_COMPANYID_1 0x12
#define SFE_VENDOR_DE_COMPANYID_2 0x87
#define SFE_VENDOR_MAX_NR_COMPONENTS 0x4
#define SFE_VENDOR_MAX_NR_SERVICES 0x3
#define SFE_VENDOR_MAX_NR_DSD_ELEMENTS 0x10
// vendor commands
#define SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL 0x0A
#define SFE_VENDOR_OPCODE_LNB_CONTROL 0x52
#define SFE_VENDOR_OPCODE_TUNE_QPSK 0x58 // QPSK command for DVB-S
// TODO: following vendor specific commands needs to be implemented
#define SFE_VENDOR_OPCODE_GET_FIRMWARE_VERSION 0x00
#define SFE_VENDOR_OPCODE_HOST2CA 0x56
#define SFE_VENDOR_OPCODE_CA2HOST 0x57
#define SFE_VENDOR_OPCODE_CISTATUS 0x59
#define SFE_VENDOR_OPCODE_TUNE_QPSK2 0x60 // QPSK command for DVB-S2 devices
// CA Tags
#define SFE_VENDOR_TAG_CA_RESET 0x00
#define SFE_VENDOR_TAG_CA_APPLICATION_INFO 0x01
#define SFE_VENDOR_TAG_CA_PMT 0x02
#define SFE_VENDOR_TAG_CA_DATE_TIME 0x04
#define SFE_VENDOR_TAG_CA_MMI 0x05
#define SFE_VENDOR_TAG_CA_ENTER_MENU 0x07
//AVCTuner DVB identifier service_ID
#define DVB 0x20
/*************************************************************
AVC descriptor types
**************************************************************/
#define Subunit_Identifier_Descriptor 0x00
#define Tuner_Status_Descriptor 0x80
typedef struct {
__u8 Subunit_Type;
__u8 Max_Subunit_ID;
} SUBUNIT_INFO;
/*************************************************************
AVCTuner DVB object IDs are 6 byte long
**************************************************************/
typedef struct {
__u8 Byte0;
__u8 Byte1;
__u8 Byte2;
__u8 Byte3;
__u8 Byte4;
__u8 Byte5;
}OBJECT_ID;
/*************************************************************
MULIPLEX Structs
**************************************************************/
typedef struct
{
#ifdef __LITTLE_ENDIAN
__u8 RF_frequency_hByte:6;
__u8 raster_Frequency:2;//Bit7,6 raster frequency
#else
__u8 raster_Frequency:2;
__u8 RF_frequency_hByte:6;
#endif
__u8 RF_frequency_mByte;
__u8 RF_frequency_lByte;
}FREQUENCY;
#ifdef __LITTLE_ENDIAN
typedef struct
{
__u8 Modulation :1;
__u8 FEC_inner :1;
__u8 FEC_outer :1;
__u8 Symbol_Rate :1;
__u8 Frequency :1;
__u8 Orbital_Pos :1;
__u8 Polarisation :1;
__u8 reserved_fields :1;
__u8 reserved1 :7;
__u8 Network_ID :1;
}MULTIPLEX_VALID_FLAGS;
typedef struct
{
__u8 GuardInterval:1;
__u8 CodeRateLPStream:1;
__u8 CodeRateHPStream:1;
__u8 HierarchyInfo:1;
__u8 Constellation:1;
__u8 Bandwidth:1;
__u8 CenterFrequency:1;
__u8 reserved1:1;
__u8 reserved2:5;
__u8 OtherFrequencyFlag:1;
__u8 TransmissionMode:1;
__u8 NetworkId:1;
}MULTIPLEX_VALID_FLAGS_DVBT;
#else
typedef struct {
__u8 reserved_fields:1;
__u8 Polarisation:1;
__u8 Orbital_Pos:1;
__u8 Frequency:1;
__u8 Symbol_Rate:1;
__u8 FEC_outer:1;
__u8 FEC_inner:1;
__u8 Modulation:1;
__u8 Network_ID:1;
__u8 reserved1:7;
}MULTIPLEX_VALID_FLAGS;
typedef struct {
__u8 reserved1:1;
__u8 CenterFrequency:1;
__u8 Bandwidth:1;
__u8 Constellation:1;
__u8 HierarchyInfo:1;
__u8 CodeRateHPStream:1;
__u8 CodeRateLPStream:1;
__u8 GuardInterval:1;
__u8 NetworkId:1;
__u8 TransmissionMode:1;
__u8 OtherFrequencyFlag:1;
__u8 reserved2:5;
}MULTIPLEX_VALID_FLAGS_DVBT;
#endif
typedef union {
MULTIPLEX_VALID_FLAGS Bits;
MULTIPLEX_VALID_FLAGS_DVBT Bits_T;
struct {
__u8 ByteHi;
__u8 ByteLo;
} Valid_Word;
} M_VALID_FLAGS;
typedef struct
{
#ifdef __LITTLE_ENDIAN
__u8 ActiveSystem;
__u8 reserved:5;
__u8 NoRF:1;
__u8 Moving:1;
__u8 Searching:1;
__u8 SelectedAntenna:7;
__u8 Input:1;
__u8 BER[4];
__u8 SignalStrength;
FREQUENCY Frequency;
__u8 ManDepInfoLength;
__u8 PowerSupply:1;
__u8 FrontEndPowerStatus:1;
__u8 reserved3:1;
__u8 AntennaError:1;
__u8 FrontEndError:1;
__u8 reserved2:3;
__u8 CarrierNoiseRatio[2];
__u8 reserved4[2];
__u8 PowerSupplyVoltage;
__u8 AntennaVoltage;
__u8 FirewireBusVoltage;
__u8 CaMmi:1;
__u8 reserved5:7;
__u8 reserved6:1;
__u8 CaInitializationStatus:1;
__u8 CaErrorFlag:1;
__u8 CaDvbFlag:1;
__u8 CaModulePresentStatus:1;
__u8 CaApplicationInfo:1;
__u8 CaDateTimeRequest:1;
__u8 CaPmtReply:1;
#else
__u8 ActiveSystem;
__u8 Searching:1;
__u8 Moving:1;
__u8 NoRF:1;
__u8 reserved:5;
__u8 Input:1;
__u8 SelectedAntenna:7;
__u8 BER[4];
__u8 SignalStrength;
FREQUENCY Frequency;
__u8 ManDepInfoLength;
__u8 reserved2:3;
__u8 FrontEndError:1;
__u8 AntennaError:1;
__u8 reserved3:1;
__u8 FrontEndPowerStatus:1;
__u8 PowerSupply:1;
__u8 CarrierNoiseRatio[2];
__u8 reserved4[2];
__u8 PowerSupplyVoltage;
__u8 AntennaVoltage;
__u8 FirewireBusVoltage;
__u8 reserved5:7;
__u8 CaMmi:1;
__u8 CaPmtReply:1;
__u8 CaDateTimeRequest:1;
__u8 CaApplicationInfo:1;
__u8 CaModulePresentStatus:1;
__u8 CaDvbFlag:1;
__u8 CaErrorFlag:1;
__u8 CaInitializationStatus:1;
__u8 reserved6:1;
#endif
} ANTENNA_INPUT_INFO; // 22 Byte
#define LNBCONTROL_DONTCARE 0xff
struct dvb_diseqc_master_cmd;
struct dvb_frontend_parameters;
struct firedtv;
int avc_recv(struct firedtv *fdtv, u8 *data, size_t length);
int AVCTuner_DSIT(struct firedtv *fdtv, int Source_Plug,
struct dvb_frontend_parameters *params, __u8 *status);
int avc_tuner_status(struct firedtv *fdtv,
ANTENNA_INPUT_INFO *antenna_input_info);
int avc_tuner_dsd(struct firedtv *fdtv,
struct dvb_frontend_parameters *params);
int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]);
int avc_tuner_get_ts(struct firedtv *fdtv);
int avc_identify_subunit(struct firedtv *fdtv);
int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
char conttone, char nrdiseq,
struct dvb_diseqc_master_cmd *diseqcmd);
void avc_remote_ctrl_work(struct work_struct *work);
int avc_register_remote_control(struct firedtv *fdtv);
int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
int avc_ca_reset(struct firedtv *fdtv);
int avc_ca_pmt(struct firedtv *fdtv, char *app_info, int length);
int avc_ca_get_time_date(struct firedtv *fdtv, int *interval);
int avc_ca_enter_menu(struct firedtv *fdtv);
int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len);
#endif /* _AVC_API_H */
/*
* 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/device.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <asm/byteorder.h>
#include <ieee1394.h>
#include <nodemgr.h>
#include "avc.h"
#include "cmp.h"
#include "firedtv.h"
#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL
static int cmp_read(struct firedtv *fdtv, void *buf, u64 addr, size_t len)
{
int ret;
if (mutex_lock_interruptible(&fdtv->avc_mutex))
return -EINTR;
ret = hpsb_node_read(fdtv->ud->ne, addr, buf, len);
if (ret < 0)
dev_err(&fdtv->ud->device, "CMP: read I/O error\n");
mutex_unlock(&fdtv->avc_mutex);
return ret;
}
static int cmp_lock(struct firedtv *fdtv, void *data, u64 addr, __be32 arg,
int ext_tcode)
{
int ret;
if (mutex_lock_interruptible(&fdtv->avc_mutex))
return -EINTR;
ret = hpsb_node_lock(fdtv->ud->ne, addr, ext_tcode, data,
(__force quadlet_t)arg);
if (ret < 0)
dev_err(&fdtv->ud->device, "CMP: lock I/O error\n");
mutex_unlock(&fdtv->avc_mutex);
return ret;
}
static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift)
{
return (be32_to_cpu(opcr) >> shift) & mask;
}
static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift)
{
*opcr &= ~cpu_to_be32(mask << shift);
*opcr |= cpu_to_be32((value & mask) << shift);
}
#define get_opcr_online(v) get_opcr((v), 0x1, 31)
#define get_opcr_p2p_connections(v) get_opcr((v), 0x3f, 24)
#define get_opcr_channel(v) get_opcr((v), 0x3f, 16)
#define set_opcr_p2p_connections(p, v) set_opcr((p), (v), 0x3f, 24)
#define set_opcr_channel(p, v) set_opcr((p), (v), 0x3f, 16)
#define set_opcr_data_rate(p, v) set_opcr((p), (v), 0x3, 14)
#define set_opcr_overhead_id(p, v) set_opcr((p), (v), 0xf, 10)
int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel)
{
__be32 old_opcr, opcr;
u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
int attempts = 0;
int ret;
ret = cmp_read(fdtv, &opcr, opcr_address, 4);
if (ret < 0)
return ret;
repeat:
if (!get_opcr_online(opcr)) {
dev_err(&fdtv->ud->device, "CMP: output offline\n");
return -EBUSY;
}
old_opcr = opcr;
if (get_opcr_p2p_connections(opcr)) {
if (get_opcr_channel(opcr) != channel) {
dev_err(&fdtv->ud->device,
"CMP: cannot change channel\n");
return -EBUSY;
}
dev_info(&fdtv->ud->device,
"CMP: overlaying existing connection\n");
/* We don't allocate isochronous resources. */
} else {
set_opcr_channel(&opcr, channel);
set_opcr_data_rate(&opcr, IEEE1394_SPEED_400);
/* FIXME: this is for the worst case - optimize */
set_opcr_overhead_id(&opcr, 0);
/* FIXME: allocate isochronous channel and bandwidth at IRM */
}
set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) + 1);
ret = cmp_lock(fdtv, &opcr, opcr_address, old_opcr, 2);
if (ret < 0)
return ret;
if (old_opcr != opcr) {
/*
* FIXME: if old_opcr.P2P_Connections > 0,
* deallocate isochronous channel and bandwidth at IRM
*/
if (++attempts < 6) /* arbitrary limit */
goto repeat;
return -EBUSY;
}
return 0;
}
void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel)
{
__be32 old_opcr, opcr;
u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
int attempts = 0;
if (cmp_read(fdtv, &opcr, opcr_address, 4) < 0)
return;