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

Merge branch 'internal'

This commit is contained in:
none 2021-03-18 19:03:57 +01:00
commit 0d66d5bab0
16 changed files with 448 additions and 161 deletions

View File

@ -6,6 +6,9 @@ We can only accept patches which don't break compilation for older kernels (as f
Due to this and other changes not approved by us the kernel version of the ddbridge driver might contain Due to this and other changes not approved by us the kernel version of the ddbridge driver might contain
incompatiblities to this driver package. incompatiblities to this driver package.
For installation instructions see:
http://support.digital-devices.eu/index.php?article=152
### Prepare for Building ### Prepare for Building
TBD TBD

View File

@ -119,7 +119,7 @@ static int update_flash(struct ddflash *ddf)
printf("Flash: %s\n", ddf->flash_name); printf("Flash: %s\n", ddf->flash_name);
printf("Version: %08x\n", ddf->id.hw); printf("Version: %08x\n", ddf->id.hw);
printf("REGMAP : %08x\n", ddf->id.regmap); printf("REGMAP : %08x\n", ddf->id.regmap);
if ((res = update_image(ddf, fname, 0x10000, 0x100000, 1, 0)) == 1) if ((res = update_image(ddf, fname, 0x10000, ddf->size / 2, 1, 0)) == 1)
stat |= 1; stat |= 1;
return stat; return stat;
} }

View File

@ -968,12 +968,10 @@ static int flashcmp(struct ddflash *ddf, int fs, uint32_t addr, uint32_t maxlen,
return -1; return -1;
len = off - fw_off; len = off - fw_off;
lseek(fs, fw_off, SEEK_SET); lseek(fs, fw_off, SEEK_SET);
#if 0
if (len > maxlen) { if (len > maxlen) {
printf("file too big\n"); printf("file too big\n");
return -1; return -1;
} }
#endif
//printf("flash file len %u, compare to %08x in flash: ", len, addr); //printf("flash file len %u, compare to %08x in flash: ", len, addr);
for (j = 0; j < len; j += bl, addr += bl) { for (j = 0; j < len; j += bl, addr += bl) {
if (len - j < bl) if (len - j < bl)
@ -1132,9 +1130,15 @@ static int check_fw(struct ddflash *ddf, char *fn, uint32_t *fw_off)
return -4; return -4;
} }
if (devid == ddf->id.device) { if (devid == ddf->id.device) {
if (version <= (ddf->id.hw & 0xffffff)) { if (version < (ddf->id.hw & 0xffffff)) {
printf("%s is older or same version as flash\n", fn); printf("%s is older version than flash\n", fn);
ret = -3; /* same id but no newer version */ if (!ddf->force)
ret = -3; /* same id but older newer version */
}
if (version == (ddf->id.hw & 0xffffff)) {
printf("%s is same version as flash\n", fn);
if (!ddf->force)
ret = 2; /* same and same version */
} }
} else } else
ret = 1; ret = 1;
@ -1147,7 +1151,7 @@ out:
} }
static int update_image(struct ddflash *ddf, char *fn, static int update_image(struct ddflash *ddf, char *fn,
uint32_t adr, uint32_t len, uint32_t adr, uint32_t maxlen,
int has_header, int no_change) int has_header, int no_change)
{ {
int fs, res = 0; int fs, res = 0;
@ -1167,7 +1171,7 @@ static int update_image(struct ddflash *ddf, char *fn,
printf("File %s not found \n", fn); printf("File %s not found \n", fn);
return -1; return -1;
} }
res = flashcmp(ddf, fs, adr, len, fw_off); res = flashcmp(ddf, fs, adr, maxlen, fw_off);
if (res == -2) { if (res == -2) {
printf("Flash already identical to %s\n", fn); printf("Flash already identical to %s\n", fn);
if (ddf->force) { if (ddf->force) {
@ -1177,9 +1181,9 @@ static int update_image(struct ddflash *ddf, char *fn,
} }
if (res < 0) if (res < 0)
goto out; goto out;
res = flashwrite(ddf, fs, adr, len, fw_off); res = flashwrite(ddf, fs, adr, maxlen, fw_off);
if (res == 0) { if (res == 0) {
res = flashcmp(ddf, fs, adr, len, fw_off); res = flashcmp(ddf, fs, adr, maxlen, fw_off);
if (res == -2) { if (res == -2) {
res = 1; res = 1;
printf("Flash verify OK!\n"); printf("Flash verify OK!\n");

View File

@ -113,7 +113,7 @@ int main(int argc, char*argv[])
} }
} }
if (optind < argc) { if (optind < argc) {
printf("too man arguments\n"); printf("too many arguments\n");
exit(1); exit(1);
} }

123
apps/sx8info.c Normal file
View File

@ -0,0 +1,123 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/types.h>
#include <getopt.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef int16_t s16;
typedef uint32_t u32;
typedef uint64_t u64;
#include "../ddbridge/ddbridge-mci.h"
#include "../ddbridge/ddbridge-ioctl.h"
char *Rolloff[8] = {
"0.35",
"0.25",
"0.20",
"0.10",
"0.05",
"0.15",
"rsvd",
"rsvd",
};
void print_info(struct mci_result *res)
{
if (res->status == MCI_DEMOD_STOPPED) {
printf("Demod stopped\n");
return;
}
switch (res->mode) {
case 0:
case M4_MODE_DVBSX:
if (res->dvbs2_signal_info.standard == 2) {
printf("PLS-Code: %u\n", res->dvbs2_signal_info.pls_code);
printf("Roll-Off: %s\n", Rolloff[res->dvbs2_signal_info.roll_off]);
printf("Inversion: %s\n", (res->dvbs2_signal_info.roll_off & 0x80) ? "on": "off");
printf("Frequency: %u Hz\n", res->dvbs2_signal_info.frequency);
printf("Symbol Rate: %u Symbols/s\n", res->dvbs2_signal_info.symbol_rate);
printf("Channel Power: %.2f dBm\n", (float) res->dvbs2_signal_info.channel_power / 100);
printf("Band Power: %.2f dBm\n", (float) res->dvbs2_signal_info.band_power / 100);
printf("SNR: %.2f dB\n", (float) res->dvbs2_signal_info.signal_to_noise / 100);
printf("Packet Errors: %u\n", res->dvbs2_signal_info.packet_errors);
printf("BER Numerator: %u\n", res->dvbs2_signal_info.ber_numerator);
printf("BER Denom.: %u\n", res->dvbs2_signal_info.ber_denominator);
printf("\n");
} else {
}
}
}
int mci_info(int dev, uint8_t demod)
{
struct ddb_mci_msg msg = {
.link = 0,
.cmd.command = MCI_CMD_GETSIGNALINFO,
.cmd.demod = demod
};
int ret;
int i;
ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg);
if (ret < 0) {
printf("%d %d\n", ret, errno);
return ret;
}
print_info(&msg.res);
return ret;
}
int main(int argc, char*argv[])
{
int fd = -1;
char fn[128];
uint32_t device = 0;
uint8_t demod = 0;
while (1) {
int cur_optind = optind ? optind : 1;
int option_index = 0;
int c;
static struct option long_options[] = {
{"device", required_argument, 0, 'd'},
{"demod", required_argument, 0, 'n'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "d:n:",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'd':
device = strtoul(optarg, NULL, 0);
break;
case 'n':
demod = strtoul(optarg, NULL, 0);
break;
default:
break;
}
}
if (optind < argc) {
printf("too many arguments\n");
exit(1);
}
snprintf(fn, 127, "/dev/ddbridge/card%u", device);
fd = open(fn, O_RDWR);
if (fd < 0)
return -1;
mci_info(fd, demod);
}

View File

@ -24,6 +24,7 @@
#include "ddbridge.h" #include "ddbridge.h"
#include "ddbridge-i2c.h" #include "ddbridge-i2c.h"
#include "ddbridge-io.h" #include "ddbridge-io.h"
#include "ddbridge-ioctl.h"
#include <media/dvb_net.h> #include <media/dvb_net.h>
struct workqueue_struct *ddb_wq; struct workqueue_struct *ddb_wq;
@ -3187,76 +3188,6 @@ static u16 mdio_read(struct ddb *dev, u8 adr, u8 reg, u32 mdio_base)
return ddbreadl(dev, MDIO_VAL_OFF + mdio_base); return ddbreadl(dev, MDIO_VAL_OFF + mdio_base);
} }
#define DDB_MAGIC 'd'
struct ddb_flashio {
__u8 *write_buf;
__u32 write_len;
__u8 *read_buf;
__u32 read_len;
__u32 link;
};
struct ddb_gpio {
__u32 mask;
__u32 data;
};
struct ddb_id {
__u16 vendor;
__u16 device;
__u16 subvendor;
__u16 subdevice;
__u32 hw;
__u32 regmap;
};
struct ddb_reg {
__u32 reg;
__u32 val;
};
struct ddb_mem {
__u32 off;
__u8 *buf;
__u32 len;
};
struct ddb_mdio {
__u8 adr;
__u8 reg;
__u16 val;
};
struct ddb_i2c_msg {
__u8 bus;
__u8 adr;
__u8 *hdr;
__u32 hlen;
__u8 *msg;
__u32 mlen;
};
struct ddb_mci_msg {
__u32 link;
struct mci_command cmd;
struct mci_result res;
};
#define IOCTL_DDB_FLASHIO _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio)
#define IOCTL_DDB_GPIO_IN _IOWR(DDB_MAGIC, 0x01, struct ddb_gpio)
#define IOCTL_DDB_GPIO_OUT _IOWR(DDB_MAGIC, 0x02, struct ddb_gpio)
#define IOCTL_DDB_ID _IOR(DDB_MAGIC, 0x03, struct ddb_id)
#define IOCTL_DDB_READ_REG _IOWR(DDB_MAGIC, 0x04, struct ddb_reg)
#define IOCTL_DDB_WRITE_REG _IOW(DDB_MAGIC, 0x05, struct ddb_reg)
#define IOCTL_DDB_READ_MEM _IOWR(DDB_MAGIC, 0x06, struct ddb_mem)
#define IOCTL_DDB_WRITE_MEM _IOR(DDB_MAGIC, 0x07, struct ddb_mem)
#define IOCTL_DDB_READ_MDIO _IOWR(DDB_MAGIC, 0x08, struct ddb_mdio)
#define IOCTL_DDB_WRITE_MDIO _IOR(DDB_MAGIC, 0x09, struct ddb_mdio)
#define IOCTL_DDB_READ_I2C _IOWR(DDB_MAGIC, 0x0a, struct ddb_i2c_msg)
#define IOCTL_DDB_WRITE_I2C _IOR(DDB_MAGIC, 0x0b, struct ddb_i2c_msg)
#define IOCTL_DDB_MCI_CMD _IOWR(DDB_MAGIC, 0x0c, struct ddb_mci_msg)
#define DDB_NAME "ddbridge" #define DDB_NAME "ddbridge"
static u32 ddb_num; static u32 ddb_num;

74
ddbridge/ddbridge-ioctl.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef _DDBRIDGE_IOCTL_H_
#define _DDBRIDGE_IOCTL_H_
#define DDB_MAGIC 'd'
struct ddb_flashio {
__u8 *write_buf;
__u32 write_len;
__u8 *read_buf;
__u32 read_len;
__u32 link;
};
struct ddb_gpio {
__u32 mask;
__u32 data;
};
struct ddb_id {
__u16 vendor;
__u16 device;
__u16 subvendor;
__u16 subdevice;
__u32 hw;
__u32 regmap;
};
struct ddb_reg {
__u32 reg;
__u32 val;
};
struct ddb_mem {
__u32 off;
__u8 *buf;
__u32 len;
};
struct ddb_mdio {
__u8 adr;
__u8 reg;
__u16 val;
};
struct ddb_i2c_msg {
__u8 bus;
__u8 adr;
__u8 *hdr;
__u32 hlen;
__u8 *msg;
__u32 mlen;
};
struct ddb_mci_msg {
__u32 link;
struct mci_command cmd;
struct mci_result res;
};
#define IOCTL_DDB_FLASHIO _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio)
#define IOCTL_DDB_GPIO_IN _IOWR(DDB_MAGIC, 0x01, struct ddb_gpio)
#define IOCTL_DDB_GPIO_OUT _IOWR(DDB_MAGIC, 0x02, struct ddb_gpio)
#define IOCTL_DDB_ID _IOR(DDB_MAGIC, 0x03, struct ddb_id)
#define IOCTL_DDB_READ_REG _IOWR(DDB_MAGIC, 0x04, struct ddb_reg)
#define IOCTL_DDB_WRITE_REG _IOW(DDB_MAGIC, 0x05, struct ddb_reg)
#define IOCTL_DDB_READ_MEM _IOWR(DDB_MAGIC, 0x06, struct ddb_mem)
#define IOCTL_DDB_WRITE_MEM _IOR(DDB_MAGIC, 0x07, struct ddb_mem)
#define IOCTL_DDB_READ_MDIO _IOWR(DDB_MAGIC, 0x08, struct ddb_mdio)
#define IOCTL_DDB_WRITE_MDIO _IOR(DDB_MAGIC, 0x09, struct ddb_mdio)
#define IOCTL_DDB_READ_I2C _IOWR(DDB_MAGIC, 0x0a, struct ddb_i2c_msg)
#define IOCTL_DDB_WRITE_I2C _IOR(DDB_MAGIC, 0x0b, struct ddb_i2c_msg)
#define IOCTL_DDB_MCI_CMD _IOWR(DDB_MAGIC, 0x0c, struct ddb_mci_msg)
#endif

View File

@ -392,10 +392,12 @@ static int read_status(struct dvb_frontend *fe, enum fe_status *status)
struct m4 *state = fe->demodulator_priv; struct m4 *state = fe->demodulator_priv;
struct mci_result res; struct mci_result res;
*status = 0x00;
if (!state->started)
return 0;
stat = ddb_mci_get_status(&state->mci, &res); stat = ddb_mci_get_status(&state->mci, &res);
if (stat) if (stat)
return stat; return stat;
*status = 0x00;
stat = ddb_mci_get_info(&state->mci); stat = ddb_mci_get_info(&state->mci);
if (stat) if (stat)
return stat; return stat;

View File

@ -65,7 +65,7 @@ static int lnb_command(struct ddb *dev, u32 link, u32 lnb, u32 cmd)
return 0; return 0;
} }
static int max_set_input_unlocked(struct dvb_frontend *fe, int in); static int max_set_input(struct dvb_frontend *fe, int in);
static int max_emulate_switch(struct dvb_frontend *fe, static int max_emulate_switch(struct dvb_frontend *fe,
u8 *cmd, u32 len) u8 *cmd, u32 len)
@ -79,7 +79,7 @@ static int max_emulate_switch(struct dvb_frontend *fe,
return -1; return -1;
input = cmd[3] & 3; input = cmd[3] & 3;
max_set_input_unlocked(fe, input); max_set_input(fe, input);
return 0; return 0;
} }
@ -98,7 +98,8 @@ static int max_send_master_cmd(struct dvb_frontend *fe,
return 0; return 0;
if (fmode == 4) if (fmode == 4)
max_emulate_switch(fe, cmd->msg, cmd->msg_len); if (!max_emulate_switch(fe, cmd->msg, cmd->msg_len))
return 0;
if (dvb->diseqc_send_master_cmd) if (dvb->diseqc_send_master_cmd)
dvb->diseqc_send_master_cmd(fe, cmd); dvb->diseqc_send_master_cmd(fe, cmd);

View File

@ -60,10 +60,6 @@ static int mci_reset(struct ddb_link *link)
return -1; return -1;
} }
dev_info(link->dev->dev, "MCI port OK, init time %u msecs\n", (40 - timeout) * 50); dev_info(link->dev->dev, "MCI port OK, init time %u msecs\n", (40 - timeout) * 50);
print_hex_dump(KERN_INFO, "ddbridge: MCI INIT INFO: ", DUMP_PREFIX_NONE, 16, 1,
link->dev->regs + regmap->mci_buf->base + MCI_COMMAND_SIZE,
16, false);
return 0; return 0;
} }

View File

@ -359,6 +359,7 @@ struct mci_result {
union { union {
u32 result[27]; u32 result[27];
u8 result8[27 * 4];
struct { struct {
u8 Rsvd0[3]; u8 Rsvd0[3];
u8 Flags; u8 Flags;
@ -758,6 +759,8 @@ struct mci_result {
#define L1POST_STATIC_FLAG(p) (((p)[18] >> 1) & 0x01) #define L1POST_STATIC_FLAG(p) (((p)[18] >> 1) & 0x01)
#define L1POST_STATIC_PADDING_FLAG(p) (((p)[18] >> 1) & 0x01) #define L1POST_STATIC_PADDING_FLAG(p) (((p)[18] >> 1) & 0x01)
#ifdef __KERNEL__
struct mci_base { struct mci_base {
struct list_head mci_list; struct list_head mci_list;
void *key; void *key;
@ -801,5 +804,6 @@ int mci_cmd_val(struct ddb_link *link, uint32_t cmd, uint32_t val);
extern struct mci_cfg ddb_max_sx8_cfg; extern struct mci_cfg ddb_max_sx8_cfg;
extern struct mci_cfg ddb_max_m4_cfg; extern struct mci_cfg ddb_max_m4_cfg;
#endif
#endif #endif

View File

@ -30,6 +30,10 @@ static int default_mod = 3;
module_param(default_mod, int, 0444); module_param(default_mod, int, 0444);
MODULE_PARM_DESC(default_mod, "default modulations enabled, default is 3 (1 = QPSK, 2 = 8PSK, 4 = 16APSK, ...)"); MODULE_PARM_DESC(default_mod, "default modulations enabled, default is 3 (1 = QPSK, 2 = 8PSK, 4 = 16APSK, ...)");
static int direct_mode;
module_param(direct_mode, int, 0444);
MODULE_PARM_DESC(direct_mode, "Ignore LDPC limits and assign high speed demods according to needed symbolrate.");
static const u32 MCLK = (1550000000 / 12); static const u32 MCLK = (1550000000 / 12);
/* Add 2MBit/s overhead allowance (minimum factor is 90/32400 for QPSK w/o Pilots) */ /* Add 2MBit/s overhead allowance (minimum factor is 90/32400 for QPSK w/o Pilots) */
@ -44,25 +48,19 @@ struct sx8_base {
struct mci_base mci_base; struct mci_base mci_base;
u8 tuner_use_count[SX8_TUNER_NUM]; u8 tuner_use_count[SX8_TUNER_NUM];
u32 gain_mode[SX8_TUNER_NUM];
u32 used_ldpc_bitrate[SX8_DEMOD_NUM]; u32 used_ldpc_bitrate[SX8_DEMOD_NUM];
u8 demod_in_use[SX8_DEMOD_NUM]; u8 demod_in_use[SX8_DEMOD_NUM];
u32 iq_mode; u32 iq_mode;
u32 burst_size;
u32 direct_mode;
}; };
struct sx8 { struct sx8 {
struct mci mci; struct mci mci;
struct mutex lock;
int first_time_lock; int first_time_lock;
int started; int started;
int iq_started; int iq_started;
u32 bb_mode;
u32 local_frequency;
}; };
static const u8 dvbs2_bits_per_symbol[] = { static const u8 dvbs2_bits_per_symbol[] = {
@ -126,38 +124,47 @@ static int ddb_mci_tsconfig(struct mci *state, u32 config)
static int read_status(struct dvb_frontend *fe, enum fe_status *status) static int read_status(struct dvb_frontend *fe, enum fe_status *status)
{ {
int stat; int stat = 0;
struct sx8 *state = fe->demodulator_priv; struct sx8 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base; struct mci_base *mci_base = state->mci.base;
struct sx8_base *sx8_base = (struct sx8_base *) mci_base; struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_result res; struct mci_result res;
*status = 0x00;
mutex_lock(&state->lock);
if (!state->started && !state->iq_started)
goto unlock;
stat = ddb_mci_get_status(&state->mci, &res); stat = ddb_mci_get_status(&state->mci, &res);
if (stat) if (stat)
return stat; goto unlock;
if (sx8_base->iq_mode >= 2) {
*status = 0x1f;
return stat;
}
*status = 0x00;
ddb_mci_get_info(&state->mci); ddb_mci_get_info(&state->mci);
if (res.status == SX8_DEMOD_WAIT_MATYPE) if (stat)
*status = 0x0f; goto unlock;
if (res.status == MCI_DEMOD_LOCKED) { if (res.status == MCI_DEMOD_LOCKED || res.status == SX8_DEMOD_IQ_MODE) {
*status = 0x1f; *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI |
if (state->mci.signal_info.dvbs2_signal_info.standard == 2) { FE_HAS_CARRIER | FE_HAS_SIGNAL;
if (res.status == MCI_DEMOD_LOCKED) {
mutex_lock(&mci_base->tuner_lock); mutex_lock(&mci_base->tuner_lock);
if (state->started) if (state->first_time_lock && state->started) {
sx8_base->used_ldpc_bitrate[state->mci.nr] = if (state->mci.signal_info.dvbs2_signal_info.standard == 2) {
p->symbol_rate * sx8_base->used_ldpc_bitrate[state->mci.nr] =
dvbs2_bits_per_symbol[ p->symbol_rate *
state->mci.signal_info. dvbs2_bits_per_symbol[
dvbs2_signal_info.pls_code]; state->mci.signal_info.
dvbs2_signal_info.pls_code];
} else
sx8_base->used_ldpc_bitrate[state->mci.nr] = 0;
state->first_time_lock = 0;
}
mutex_unlock(&mci_base->tuner_lock); mutex_unlock(&mci_base->tuner_lock);
} else }
sx8_base->used_ldpc_bitrate[state->mci.nr] = 0; } else if (res.status == MCI_DEMOD_TIMEOUT)
} *status = FE_TIMEDOUT;
else if (res.status >= SX8_DEMOD_WAIT_MATYPE)
*status = FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
unlock:
mutex_unlock(&state->lock);
return stat; return stat;
} }
@ -165,14 +172,12 @@ static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on,
u8 flags, u8 gain) u8 flags, u8 gain)
{ {
struct sx8 *state = fe->demodulator_priv; struct sx8 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
struct mci_command cmd; struct mci_command cmd;
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
cmd.tuner = state->mci.tuner; cmd.tuner = state->mci.tuner;
cmd.command = on ? SX8_CMD_INPUT_ENABLE : SX8_CMD_INPUT_DISABLE; cmd.command = on ? SX8_CMD_INPUT_ENABLE : SX8_CMD_INPUT_DISABLE;
cmd.sx8_input_enable.flags = flags;//sx8_base->gain_mode[state->mci.tuner]; cmd.sx8_input_enable.flags = flags;
cmd.sx8_input_enable.rf_gain = gain; cmd.sx8_input_enable.rf_gain = gain;
return ddb_mci_cmd(&state->mci, &cmd, NULL); return ddb_mci_cmd(&state->mci, &cmd, NULL);
} }
@ -202,9 +207,9 @@ static int stop_iq(struct dvb_frontend *fe)
state->mci.demod = SX8_DEMOD_NONE; state->mci.demod = SX8_DEMOD_NONE;
} }
sx8_base->used_ldpc_bitrate[state->mci.nr] = 0; sx8_base->used_ldpc_bitrate[state->mci.nr] = 0;
mutex_unlock(&mci_base->tuner_lock);
sx8_base->iq_mode = 0; sx8_base->iq_mode = 0;
state->iq_started = 0; state->iq_started = 0;
mutex_unlock(&mci_base->tuner_lock);
return 0; return 0;
} }
@ -214,12 +219,13 @@ static int stop(struct dvb_frontend *fe)
struct mci_base *mci_base = state->mci.base; struct mci_base *mci_base = state->mci.base;
struct sx8_base *sx8_base = (struct sx8_base *) mci_base; struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
struct mci_command cmd; struct mci_command cmd;
u32 input = state->mci.tuner; u32 input;
input = state->mci.tuner;
if (!state->started) if (!state->started)
return -1; return -1;
memset(&cmd, 0, sizeof(cmd));
if (state->mci.demod != SX8_DEMOD_NONE) { if (state->mci.demod != SX8_DEMOD_NONE) {
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_STOP; cmd.command = MCI_CMD_STOP;
cmd.demod = state->mci.demod; cmd.demod = state->mci.demod;
ddb_mci_cmd(&state->mci, &cmd, NULL); ddb_mci_cmd(&state->mci, &cmd, NULL);
@ -241,8 +247,8 @@ static int stop(struct dvb_frontend *fe)
} }
sx8_base->used_ldpc_bitrate[state->mci.nr] = 0; sx8_base->used_ldpc_bitrate[state->mci.nr] = 0;
sx8_base->iq_mode = 0; sx8_base->iq_mode = 0;
mutex_unlock(&mci_base->tuner_lock);
state->started = 0; state->started = 0;
mutex_unlock(&mci_base->tuner_lock);
return 0; return 0;
} }
@ -260,6 +266,10 @@ static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config)
u32 bits_per_symbol = 0; u32 bits_per_symbol = 0;
int i = -1, stat = 0; int i = -1, stat = 0;
struct ddb_link *link = state->mci.base->link; struct ddb_link *link = state->mci.base->link;
const u8 ro_lut[8] = {
8 | SX8_ROLLOFF_35, 8 | SX8_ROLLOFF_20, 8 | SX8_ROLLOFF_25, 0,
8 | SX8_ROLLOFF_15, 8 | SX8_ROLLOFF_10, 8 | SX8_ROLLOFF_05, 0,
};
if (link->ids.device == 0x000b) { if (link->ids.device == 0x000b) {
/* Mask out higher modulations and MIS for Basic /* Mask out higher modulations and MIS for Basic
@ -287,7 +297,7 @@ static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config)
goto unlock; goto unlock;
} }
if (sx8_base->direct_mode) { if (direct_mode) {
if (p->symbol_rate >= MCLK / 2) { if (p->symbol_rate >= MCLK / 2) {
if (state->mci.nr < 4) if (state->mci.nr < 4)
i = state->mci.nr; i = state->mci.nr;
@ -316,9 +326,8 @@ static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config)
stat = -EBUSY; stat = -EBUSY;
goto unlock; goto unlock;
} }
modmask &= ((1 << (bits_per_symbol - 1)) - 1); modmask &= ((1 << (bits_per_symbol - 1)) - 1);
if( ((flags & 0x02) != 0) && (modmask == 0)) { if (((flags & 0x02) != 0) && (modmask == 0)) {
stat = -EBUSY; stat = -EBUSY;
goto unlock; goto unlock;
} }
@ -344,11 +353,10 @@ unlock:
if (stat) if (stat)
return stat; return stat;
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
if (sx8_base->iq_mode) { if (sx8_base->iq_mode) {
cmd.command = SX8_CMD_ENABLE_IQOUTPUT; cmd.command = SX8_CMD_ENABLE_IQOUTPUT;
cmd.demod = state->mci.demod; cmd.demod = state->mci.demod;
cmd.output = p->stream_id & 7; cmd.output = p->stream_id & 0x0f;
ddb_mci_cmd(&state->mci, &cmd, NULL); ddb_mci_cmd(&state->mci, &cmd, NULL);
ddb_mci_tsconfig(&state->mci, ts_config); ddb_mci_tsconfig(&state->mci, ts_config);
} }
@ -364,6 +372,7 @@ unlock:
cmd.command = MCI_CMD_SEARCH_DVBS; cmd.command = MCI_CMD_SEARCH_DVBS;
cmd.dvbs2_search.flags = flags; cmd.dvbs2_search.flags = flags;
cmd.dvbs2_search.s2_modulation_mask = modmask; cmd.dvbs2_search.s2_modulation_mask = modmask;
cmd.dvbs2_search.rsvd1 = ro_lut[p->rolloff & 7];
cmd.dvbs2_search.retry = 2; cmd.dvbs2_search.retry = 2;
cmd.dvbs2_search.frequency = p->frequency * 1000; cmd.dvbs2_search.frequency = p->frequency * 1000;
cmd.dvbs2_search.symbol_rate = p->symbol_rate; cmd.dvbs2_search.symbol_rate = p->symbol_rate;
@ -377,6 +386,9 @@ unlock:
(p->stream_id & 0x80000000)) (p->stream_id & 0x80000000))
cmd.output |= 0x80; cmd.output |= 0x80;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL); stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
state->started = 1;
state->first_time_lock = 1;
state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL;
if (stat) if (stat)
stop(fe); stop(fe);
return stat; return stat;
@ -395,8 +407,8 @@ static int start_iq(struct dvb_frontend *fe, u32 flags,
u32 input = state->mci.tuner; u32 input = state->mci.tuner;
int i, stat = 0; int i, stat = 0;
mutex_lock(&mci_base->tuner_lock);
if (!state->iq_started) { if (!state->iq_started) {
mutex_lock(&mci_base->tuner_lock);
if (sx8_base->iq_mode) { if (sx8_base->iq_mode) {
stat = -EBUSY; stat = -EBUSY;
goto unlock; goto unlock;
@ -409,17 +421,18 @@ static int start_iq(struct dvb_frontend *fe, u32 flags,
goto unlock; goto unlock;
} }
state->mci.demod = 0; state->mci.demod = 0;
/*
if (!sx8_base->tuner_use_count[input])
mci_set_tuner(fe, input, 1);
*/
sx8_base->tuner_use_count[input]++; sx8_base->tuner_use_count[input]++;
sx8_base->iq_mode = 2; sx8_base->iq_mode = 2;
unlock: } else {
mutex_unlock(&mci_base->tuner_lock); if ((state->iq_started & 0x07) != state->mci.nr) {
if (stat) stat = -EBUSY;
return stat; goto unlock;
}
} }
unlock:
mutex_unlock(&mci_base->tuner_lock);
if (stat)
return stat;
mci_set_tuner(fe, input, 1, flags & 0xff, 0); mci_set_tuner(fe, input, 1, flags & 0xff, 0);
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
cmd.command = SX8_CMD_START_IQ; cmd.command = SX8_CMD_START_IQ;
@ -431,6 +444,9 @@ static int start_iq(struct dvb_frontend *fe, u32 flags,
cmd.tuner = state->mci.tuner; cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod; cmd.demod = state->mci.demod;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL); stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
state->iq_started = 8 | state->mci.nr;
state->first_time_lock = 1;
state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL;
if (stat) if (stat)
stop_iq(fe); stop_iq(fe);
ddb_mci_tsconfig(&state->mci, ts_config); ddb_mci_tsconfig(&state->mci, ts_config);
@ -443,7 +459,6 @@ static int set_lna(struct dvb_frontend *fe)
return 0; return 0;
} }
static int set_parameters(struct dvb_frontend *fe) static int set_parameters(struct dvb_frontend *fe)
{ {
int stat = 0; int stat = 0;
@ -459,6 +474,7 @@ static int set_parameters(struct dvb_frontend *fe)
state->mci.input->con = ts_mode << 8; state->mci.input->con = ts_mode << 8;
if (iq_mode) if (iq_mode)
ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ); ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ);
mutex_lock(&state->lock);
stop(fe); stop(fe);
if (iq_mode < 2) { if (iq_mode < 2) {
u32 mask; u32 mask;
@ -485,19 +501,10 @@ static int set_parameters(struct dvb_frontend *fe)
break; break;
} }
stat = start(fe, 3, mask, ts_config); stat = start(fe, 3, mask, ts_config);
if (!stat) {
state->started = 1;
state->first_time_lock = 1;
state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL;
}
} else { } else {
stat = start_iq(fe, isi & 0xffffff, 4, ts_config); stat = start_iq(fe, isi & 0xffffff, 4, ts_config);
if (!stat) {
state->iq_started = 1;
state->first_time_lock = 1;
state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL;
}
} }
mutex_unlock(&state->lock);
return stat; return stat;
} }
@ -536,16 +543,22 @@ static int set_input(struct dvb_frontend *fe, int input)
return -EINVAL; return -EINVAL;
if (state->mci.tuner == input) if (state->mci.tuner == input)
return 0; return 0;
mutex_lock(&state->lock);
stop_iq(fe); stop_iq(fe);
stop(fe); stop(fe);
state->mci.tuner = p->input = input; state->mci.tuner = p->input = input;
mutex_unlock(&state->lock);
return 0; return 0;
} }
static int sleep(struct dvb_frontend *fe) static int sleep(struct dvb_frontend *fe)
{ {
struct sx8 *state = fe->demodulator_priv;
mutex_lock(&state->lock);
stop_iq(fe); stop_iq(fe);
stop(fe); stop(fe);
mutex_unlock(&state->lock);
return 0; return 0;
} }
@ -591,6 +604,7 @@ static int init(struct mci *mci)
state->mci.demod = SX8_DEMOD_NONE; state->mci.demod = SX8_DEMOD_NONE;
mci->fe.ops.xbar[1] = mci->nr; mci->fe.ops.xbar[1] = mci->nr;
mci->fe.dtv_property_cache.input = mci->tuner; mci->fe.dtv_property_cache.input = mci->tuner;
mutex_init(&state->lock);
return 0; return 0;
} }

View File

@ -208,17 +208,35 @@ static int write_field(struct stv *state, u32 field, u8 val)
return write_reg(state, field >> 16, new); return write_reg(state, field >> 16, new);
} }
static int read_field(struct stv *state, u32 field, u8 *val)
{
int status;
u8 shift, mask;
status = read_reg(state, field >> 16, val);
if (status)
return status;
mask = field & 0xff;
shift = (field >> 12) & 0xf;
*val = (*val & mask) >> shift;
return status;
}
#define set_field(_reg, _val) \ #define set_field(_reg, _val) \
write_field(state, state->nr ? FSTV0910_P2_##_reg : \ write_field(state, state->nr ? FSTV0910_P2_##_reg : \
FSTV0910_P1_##_reg, _val) FSTV0910_P1_##_reg, _val)
#define get_field(_reg, _val) \
read_field(state, state->nr ? FSTV0910_P2_##_reg : \
FSTV0910_P1_##_reg, _val)
#define set_reg(_reg, _val) \ #define set_reg(_reg, _val) \
write_reg(state, state->nr ? RSTV0910_P2_##_reg : \ write_reg(state, state->nr ? RSTV0910_P2_##_reg : \
RSTV0910_P1_##_reg, _val) RSTV0910_P1_##_reg, _val)
#define get_reg(_reg, _val) \ #define get_reg(_reg, _val) \
read_reg(state, state->nr ? RSTV0910_P2_##_reg : \ read_reg(state, state->nr ? RSTV0910_P2_##_reg : \
RTV0910_P1_##_reg, _val) RSTV0910_P1_##_reg, _val)
static const struct slookup s1_sn_lookup[] = { static const struct slookup s1_sn_lookup[] = {
{ 0, 9242 }, /* C/N= 0dB */ { 0, 9242 }, /* C/N= 0dB */
@ -1112,8 +1130,9 @@ static int init_diseqc(struct stv *state)
u16 offs = state->nr ? 0x40 : 0; /* Address offset */ u16 offs = state->nr ? 0x40 : 0; /* Address offset */
u8 freq = ((state->base->mclk + 11000 * 32) / (22000 * 32)); u8 freq = ((state->base->mclk + 11000 * 32) / (22000 * 32));
/* Disable receiver */ write_reg(state, RSTV0910_P1_DISRXCFG + offs, 0x05);
write_reg(state, RSTV0910_P1_DISRXCFG + offs, 0x00); //write_reg(state, RSTV0910_P1_DISRXF220 + offs, 0x69); 2b?
write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0xBA); /* Reset = 1 */ write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0xBA); /* Reset = 1 */
write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A); /* Reset = 0 */ write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A); /* Reset = 0 */
write_reg(state, RSTV0910_P1_DISTXF22 + offs, freq); write_reg(state, RSTV0910_P1_DISTXF22 + offs, freq);
@ -1617,12 +1636,28 @@ static int wait_dis(struct stv *state, u8 flag, u8 val)
return -1; return -1;
} }
static int clear_slave(struct dvb_frontend *fe)
{
struct stv *state = fe->demodulator_priv;
u8 n, d, done;
get_field(RXEND, &done);
get_reg(DISRXBYTES, &n);
printk("clear: done = %u, %u fifo bytes\n", done, n);
for (get_reg(DISRXBYTES, &n); n; n--)
get_reg(DISRXFIFO, &d);
return 0;
}
static int send_master_cmd(struct dvb_frontend *fe, static int send_master_cmd(struct dvb_frontend *fe,
struct dvb_diseqc_master_cmd *cmd) struct dvb_diseqc_master_cmd *cmd)
{ {
struct stv *state = fe->demodulator_priv; struct stv *state = fe->demodulator_priv;
int i; int i;
clear_slave(fe);
set_field(DISRX_ON, 0);
set_reg(DISTXCFG, 0x3e); set_reg(DISTXCFG, 0x3e);
for (i = 0; i < cmd->msg_len; i++) { for (i = 0; i < cmd->msg_len; i++) {
wait_dis(state, 0x40, 0x00); wait_dis(state, 0x40, 0x00);
@ -1630,12 +1665,59 @@ static int send_master_cmd(struct dvb_frontend *fe,
} }
set_reg(DISTXCFG, 0x3a); set_reg(DISTXCFG, 0x3a);
wait_dis(state, 0x20, 0x20); wait_dis(state, 0x20, 0x20);
set_field(DISRX_ON, 1);
return 0; return 0;
} }
static int recv_slave_reply(struct dvb_frontend *fe, static int recv_slave_reply(struct dvb_frontend *fe,
struct dvb_diseqc_slave_reply *reply) struct dvb_diseqc_slave_reply *reply)
{ {
struct stv *state = fe->demodulator_priv;
int i, to, flag = 0, max = sizeof(reply->msg);
u8 done, val, n = 0;
#if 0
get_reg(DISRXBYTES, &val);
get_field(RXEND, &done);
printk("slave: done = %u, %u fifo bytes\n", done, val);
#endif
to = reply->timeout;
if (to < 0) {
to = 100;
flag = 1;
} else if (to > 5000)
to = 100;
reply->msg_len = 0;
for (i = 0; i < to; i += 10) {
get_reg(DISRXBYTES, &val);
if (flag && val)
break;
get_field(RXEND, &done);
if (val >= max || done)
break;
msleep(10);
}
get_reg(DISRXBYTES, &val);
printk("done = %u, %u fifo bytes, i=%u\n", done, val, i);
if (i == to && !val)
return -EIO;
if (done && !val)
return -EIO;
for (i = 100; i; i--) {
get_field(RXEND, &done);
for (get_reg(DISRXBYTES, &n); n; n--) {
if (reply->msg_len == max)
return 0;
get_reg(DISRXFIFO, &reply->msg[reply->msg_len++]);
}
if (!n || done)
break;
msleep(10);
}
if (!i)
return -EIO;
return 0; return 0;
} }

49
lib/README.md Normal file
View File

@ -0,0 +1,49 @@
# LIBDDDVB
The libdddvb provides a userspace library to simplify tuning and
CI use. It detects DVB cards and their capabilities and selects
free frontends depending on a given delivery system.
In order to install the libdddvb library you need the dvben50221.
On an Ubuntu and other Debian based system you can install it like this:
`sudo apt-get install dvb-apps`
After that you can build the libdddvb:
`git clone https://github.com/DigitalDevices/dddvb.git`
`cd dddvb/lib/; make`
`sudo make install`
If your distribution does not include a dvb-apps package, you can follow the
instructions at
https://www.linuxtv.org/wiki/index.php/LinuxTV_dvb-apps
on how to build it yourself.
# DDZAP
You can now use the example program ddzap to see how the library
is used or to test your cards.
A typical usage example would be the tuning of a
sattelite channel with a given LNB configuration.
`ddzap -d S2 -p h -f 11494000 -s 22000000 -c ~/dddvb/lib/config/`
where you would use the example configuration file for a unicable LNB
given in the sources. If you leave out the `-c` option a standard universal
LNB is assumed to be connected.
Additionally you can use ddzap to open the /dev/dvb/adaptorX/dvrY device
that corresponds to the tuner that was automatically selected by the library
and pipe it to a media player, e.g.
`ddzap -d S2 -p h -f 11494000 -s 22000000 -c /home/dmocm/ddzapconf/ -o|vlc -`

View File

@ -271,7 +271,7 @@ int main(int argc, char **argv)
struct dddvb_fe *fe; struct dddvb_fe *fe;
struct dddvb_params p; struct dddvb_params p;
uint32_t bandwidth = DDDVB_UNDEF, frequency = 0, symbol_rate = 0, pol = DDDVB_UNDEF; uint32_t bandwidth = DDDVB_UNDEF, frequency = 0, symbol_rate = 0, pol = DDDVB_UNDEF;
uint32_t id = DDDVB_UNDEF, ssi = DDDVB_UNDEF, num = DDDVB_UNDEF, source = 0; uint32_t id = DDDVB_UNDEF, ssi = DDDVB_UNDEF, num = DDDVB_UNDEF, source = DDDVB_UNDEF;
uint32_t mtype= DDDVB_UNDEF; uint32_t mtype= DDDVB_UNDEF;
uint32_t verbosity = 0; uint32_t verbosity = 0;
uint32_t get_ts = 1; uint32_t get_ts = 1;

View File

@ -288,7 +288,8 @@ static int tune_sat(struct dddvb_fe *fe)
freq = lofs - freq; freq = lofs - freq;
} }
#endif #endif
if (freq > 2100000) {
if (freq > 3000000) {
if (lofs) if (lofs)
hi = (freq > lofs) ? 1 : 0; hi = (freq > lofs) ? 1 : 0;
if (hi) if (hi)
@ -318,14 +319,15 @@ static int tune_sat(struct dddvb_fe *fe)
fe->scif_slot, fe->scif_freq, ds); fe->scif_slot, fe->scif_freq, ds);
pthread_mutex_unlock(&fe->dd->uni_lock); pthread_mutex_unlock(&fe->dd->uni_lock);
} else { } else {
uint32_t input = lnb; uint32_t input = fe->param.param[PARAM_SRC];
//if (input != DDDVB_UNDEF) if (input != DDDVB_UNDEF) {
// input = 3 & (input >> 6); input = 3 & (input >> 6);
//set_property(fe->fd, DTV_INPUT, 3 & (lnb >> 6)); printf("input = %u\n", input);
}
diseqc(fe->fd, lnb, fe->param.param[PARAM_POL], hi); diseqc(fe->fd, lnb, fe->param.param[PARAM_POL], hi);
//set_fe_input(fe, freq, fe->param.param[PARAM_SR], ds, input); set_fe_input(fe, freq, fe->param.param[PARAM_SR], ds, input);
set_fe_input(fe, freq, fe->param.param[PARAM_SR], ds, ~(0U)); //set_fe_input(fe, freq, fe->param.param[PARAM_SR], ds, DDDVB_UNDEF);
} }
} }
@ -750,6 +752,8 @@ int dddvb_fe_tune(struct dddvb_fe *fe, struct dddvb_params *p)
memcpy(fe->n_param.param, p->param, sizeof(fe->n_param.param)); memcpy(fe->n_param.param, p->param, sizeof(fe->n_param.param));
fe->n_tune = 1; fe->n_tune = 1;
pthread_mutex_unlock(&fe->mutex); pthread_mutex_unlock(&fe->mutex);
while(fe->n_tune) usleep(10000);
while(fe->tune != 2) usleep(10000);
return ret; return ret;
} }