diff --git a/apps/Makefile b/apps/Makefile index 31a1ed5..44ddd15 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -1,4 +1,4 @@ -all: cit citin flashprog modt ddtest setmod ddflash setmod2 pls setmod3 +all: cit citin flashprog modt ddtest setmod ddflash setmod2 pls setmod3 modconfig cit: cit.c $(CC) -o cit cit.c -lpthread @@ -15,6 +15,9 @@ setmod2: setmod2.c setmod3: setmod3.c $(CC) -o setmod3 setmod3.c -I../include/ +modconfig: modconfig.c + $(CC) -o modconfig modconfig.c -I../include/ + %.o: %.c $(CC) $(CFLAGS) -o $@ $< diff --git a/apps/modconfig.c b/apps/modconfig.c new file mode 100644 index 0000000..ce1c95b --- /dev/null +++ b/apps/modconfig.c @@ -0,0 +1,268 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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" + +struct mconf { + int set_output; + int set_channels; + int fd; + + struct mci_command channels; + struct mci_command stream; + struct mci_command output; +}; + +void strim(char *s) +{ + int l = strlen(s); + + while (l && isspace(s[l-1])) + l--; + s[l] = 0; +} + +void parse(char *fname, char *sec, void *priv, void (*cb)(void *, char *, char *)) +{ + char line[256], csec[80], par[80], val[80], *p; + FILE *f; + + if ((f = fopen(fname, "r")) == NULL) + return; + while ((p = fgets(line, sizeof(line), f))) { + if (*p == '\r' || *p == '\n' || *p == '#') + continue; + if (*p == '[') { + if ((p = strtok(line + 1, "]")) == NULL) + continue; + strncpy(csec, p, sizeof(csec)); + if (!strcmp(sec, csec) && cb) + cb(priv, NULL, NULL); + continue; + } + if (!(p = strtok(line, "="))) + continue; + while (isspace(*p)) + p++; + strncpy(par, p, sizeof(par)); + strim(par); + if (!(p = strtok(NULL, "="))) + continue; + while (isspace(*p)) + p++; + strncpy (val, p, sizeof(val)); + strim(val); + if (!strcmp(sec, csec) && cb) + cb(priv, par, val); + } + if (!strcmp(sec, csec) && cb) + cb(priv, NULL, NULL); + fclose(f); +} + +int mci_cmd(int dev, struct mci_command *cmd) +{ + int ret; + struct ddb_mci_msg msg; + + msg.link = 0; + memcpy(&msg.cmd, cmd, sizeof(msg.cmd)); + ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg); + if (ret < 0) { + printf("mci_cmd error %d\n", errno); + return ret; + } + return ret; +} + +struct mci_command msg_channels = { + .mod_command = MOD_SETUP_CHANNELS, + .mod_channel = 0, + .mod_stream = 0, + .mod_setup_channels[0] = { + .flags = MOD_SETUP_FLAG_FIRST|MOD_SETUP_FLAG_LAST|MOD_SETUP_FLAG_VALID, + .standard = MOD_STANDARD_DVBT_8, + .num_channels = 25, + .frequency = 474000000, + }, +}; + +struct mci_command msg_stream = { + .mod_command = MOD_SETUP_STREAM, + .mod_channel = 1, + .mod_stream = 0, + .mod_setup_stream = { + .standard = MOD_STANDARD_DVBT_8, + .fft_size = 1, + .guard_interval = 0, + }, +}; + +struct mci_command msg_output = { + .mod_command = MOD_SETUP_OUTPUT, + .mod_channel = 0, + .mod_stream = 0, + .mod_setup_output = { + .connector = MOD_CONNECTOR_F, + .num_channels = 16, + .unit = MOD_UNIT_DBUV, + .channel_power = 5000, + }, +}; + +void output_cb(void *priv, char *par, char *val) +{ + struct mconf *mc = (struct mconf *) priv; + + if (!par && !val) { + mc->set_output = 1; + return; + } + if (!strcasecmp(par, "connector")) { + if (!strcasecmp(val, "F")) { + mc->output.mod_setup_output.connector = MOD_CONNECTOR_F; + } else if (!strcasecmp(val, "SMA")) { + mc->output.mod_setup_output.connector = MOD_CONNECTOR_SMA; + } else if (!strcasecmp(val, "OFF")) { + mc->output.mod_setup_output.connector = MOD_CONNECTOR_OFF; + } else + printf("invalid connector\n"); + } else if (!strcasecmp(par, "power")) { + mc->output.mod_setup_output.channel_power = strtol(val, NULL, 10); + } else if (!strcasecmp(par, "channels")) { + mc->output.mod_setup_output.num_channels = strtol(val, NULL, 10); + }else if (!strcasecmp(par, "unit")) { + if (!strcasecmp(val, "DBUV")) { + mc->output.mod_setup_output.unit = MOD_UNIT_DBUV; + } else if (!strcasecmp(val, "DBM")) { + mc->output.mod_setup_output.unit = MOD_UNIT_DBM; + } else + printf("invalid unit\n"); + } else + printf("invalid output parameter: %s\n", par); +} + +void channels_cb(void *priv, char *par, char *val) +{ + struct mconf *mc = (struct mconf *) priv; + + if (!par && !val) { + mc->set_channels = 1; + return; + } + if (!strcasecmp(par, "frequency")) { + mc->channels.mod_setup_channels[0].frequency = strtol(val, NULL, 10); + printf("frequency = %u\n", mc->channels.mod_setup_channels[0].frequency); + } else if (!strcasecmp(par, "channels")) { + mc->channels.mod_setup_channels[0].num_channels = strtol(val, NULL, 10); + } else if (!strcasecmp(par, "standard")) { + mc->channels.mod_setup_channels[0].standard = strtol(val, NULL, 10); + } else if (!strcasecmp(par, "offset")) { + mc->channels.mod_setup_channels[0].offset = strtol(val, NULL, 10); + } else if (!strcasecmp(par, "bandwidth")) { + mc->channels.mod_setup_channels[0].bandwidth = strtol(val, NULL, 10); + mc->channels.mod_setup_channels[0].offset = + mc->channels.mod_setup_channels[0].bandwidth / 2; + } else + printf("invalid channels parameter: %s\n", par); +} + +void streams_cb(void *priv, char *par, char *val) +{ + struct mconf *mc = (struct mconf *) priv; + + if (!par && !val) { + return; + } + if (!strcasecmp(par, "fft_size")) { + mc->stream.mod_setup_stream.fft_size = strtol(val, NULL, 10); + } else if (!strcasecmp(par, "guard_interval")) { + mc->stream.mod_setup_stream.guard_interval = strtol(val, NULL, 10); + } else if (!strcasecmp(par, "standard")) { + mc->stream.mod_setup_stream.standard = strtol(val, NULL, 10); + } else if (!strcasecmp(par, "stream_format")) { + mc->stream.mod_setup_stream.stream_format = strtol(val, NULL, 10); + } else if (!strcasecmp(par, "symbol_rate")) { + mc->stream.mod_setup_stream.symbol_rate = strtol(val, NULL, 10); + } else if (!strcasecmp(par, "stream")) { + mc->stream.mod_stream = strtol(val, NULL, 10); + printf("set stream %u to channel %u\n", mc->stream.mod_stream, mc->stream.mod_channel); + mci_cmd(mc->fd, &mc->stream); + } else if (!strcasecmp(par, "channel")) { + mc->stream.mod_channel = strtol(val, NULL, 10); + } else + printf("invalid streams parameter: %s\n", par); +} + +int main(int argc, char*argv[]) +{ + int fd = -1; + char fn[128]; + uint32_t device = 0; + uint32_t frequency = 0; + char *configname = "modulator.conf"; + struct mconf mc; + + memset(&mc, 0, sizeof(mc)); + mc.channels = msg_channels; + mc.stream = msg_stream; + mc.output = msg_output; + + while (1) { + int cur_optind = optind ? optind : 1; + int option_index = 0; + int c; + static struct option long_options[] = { + {"device", required_argument, 0, 'd'}, + {"config", required_argument, 0, 'c'}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "d:c:", + long_options, &option_index); + if (c == -1) + break; + switch (c) { + case 'd': + device = strtoul(optarg, NULL, 0); + break; + case 'c': + configname = optarg; + 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; + mc.fd = fd; + parse(configname, "output", (void *) &mc, output_cb); + if (mc.set_output) + mci_cmd(fd, &mc.output); + parse(configname, "channels", (void *) &mc, channels_cb); + if (mc.set_channels) + mci_cmd(fd, &mc.channels); + parse(configname, "streams", (void *) &mc, streams_cb); +} diff --git a/apps/modulator.conf b/apps/modulator.conf new file mode 100644 index 0000000..1d92b27 --- /dev/null +++ b/apps/modulator.conf @@ -0,0 +1,22 @@ +[output] +connector = F +channels = 16 +unit = DBUV +power = 5000 + +[channels] +standard = 1 +channels = 25 +frequency = 474000000 + +[streams] +guard_interval = 0 +fft_size = 1 + +channel = 1 +stream = 0 + +channel = 0 +stream = 1 + + diff --git a/ddbridge/ddbridge-main.c b/ddbridge/ddbridge-main.c index f84536c..631ad86 100644 --- a/ddbridge/ddbridge-main.c +++ b/ddbridge/ddbridge-main.c @@ -312,6 +312,7 @@ static int __devinit ddb_probe(struct pci_dev *pdev, dev->link[0].ids.subvendor = id->subvendor; dev->link[0].ids.subdevice = pdev->subsystem_device; dev->link[0].ids.devid = (id->device << 16) | id->vendor; + dev->link[0].ids.revision = pdev->revision; dev->link[0].dev = dev; dev->link[0].info = get_ddb_info(id->vendor, id->device, diff --git a/ddbridge/ddbridge-mci.c b/ddbridge/ddbridge-mci.c index 4b5bff4..5cf9da4 100644 --- a/ddbridge/ddbridge-mci.c +++ b/ddbridge/ddbridge-mci.c @@ -34,10 +34,16 @@ static int mci_reset(struct ddb_link *link) u32 control; u32 status = 0; u32 timeout = 40; - - if (!regmap || ! regmap->mci) + union { + u32 u[4]; + char s[16]; + } version; + u32 vaddr; + + if (!regmap || !regmap->mci) return -EINVAL; control = regmap->mci->base; + vaddr = regmap->mci_buf->base + 0xf0; if ((link->info->type == DDB_OCTOPUS_MCI) && (ddblreadl(link, control) & MCI_CONTROL_START_COMMAND)) { @@ -55,11 +61,17 @@ static int mci_reset(struct ddb_link *link) msleep(50); } dev_info(link->dev->dev, "MCI control port @ %08x\n", control); + if ((status & MCI_CONTROL_READY) == 0) { dev_err(link->dev->dev, "MCI init failed!\n"); return -1; } + version.u[0] = ddblreadl(link, vaddr); + version.u[1] = ddblreadl(link, vaddr + 4); + version.u[2] = ddblreadl(link, vaddr + 8); + version.u[3] = ddblreadl(link, vaddr + 12); dev_info(link->dev->dev, "MCI port OK, init time %u msecs\n", (40 - timeout) * 50); + dev_info(link->dev->dev, "MCI firmware version %s.%d\n", version.s, version.s[15]); return 0; } @@ -108,6 +120,7 @@ static int ddb_mci_cmd_raw_unlocked(struct ddb_link *link, 0xffffff, INTERRUPT_ACK); } } + //print_hex_dump(KERN_INFO, "MCI", DUMP_PREFIX_OFFSET, 16, 1, cmd, cmd_len, false); if (res && res_len) for (i = 0; i < res_len; i++) res[i] = ddblreadl(link, result + i * 4); @@ -166,17 +179,10 @@ int mci_init(struct ddb_link *link) int mci_cmd_val(struct ddb_link *link, uint32_t cmd, uint32_t val) { struct mci_result result; -#if 0 - struct mci_command command = { - .command_word = cmd, - .params = { val }, - }; -#else struct mci_command command; command.command_word = cmd; command.params[0] = val; -#endif return ddb_mci_cmd_link(link, &command, &result); } diff --git a/ddbridge/ddbridge-mci.h b/ddbridge/ddbridge-mci.h index d770a6d..e38669e 100644 --- a/ddbridge/ddbridge-mci.h +++ b/ddbridge/ddbridge-mci.h @@ -185,6 +185,60 @@ #define MCI_SUCCESS(status) ((status & MCI_STATUS_UNSUPPORTED) == 0) +/********************************************************/ + +#define MOD_SETUP_CHANNELS (0x60) +#define MOD_SETUP_OUTPUT (0x61) +#define MOD_SETUP_STREAM (0x62) + +#define MOD_SETUP_FLAG_FIRST (0x01) +#define MOD_SETUP_FLAG_LAST (0x02) +#define MOD_SETUP_FLAG_VALID (0x80) + +#define MOD_STANDARD_GENERIC (0x00) +#define MOD_STANDARD_DVBT_8 (0x01) +#define MOD_STANDARD_DVBT_7 (0x02) +#define MOD_STANDARD_DVBT_6 (0x03) + +#define MOD_CONNECTOR_OFF (0x00) +#define MOD_CONNECTOR_F (0x01) +#define MOD_CONNECTOR_SMA (0x02) + +#define MOD_UNIT_DBUV (0x00) +#define MOD_UNIT_DBM (0x01) + +#define MOD_FORMAT_DEFAULT (0x00) +#define MOD_FORMAT_IQ16 (0x01) +#define MOD_FORMAT_IQ8 (0x02) +#define MOD_FORMAT_IDX8 (0x03) +#define MOD_FORMAT_TS (0x04) + +struct mod_setup_channels { + u8 flags; + u8 standard; + u8 num_channels; + u8 rsvd; + u32 frequency; + u32 offset; /* used only when Standard == 0 */ + u32 bandwidth; /* used only when Standard == 0 */ +}; + +struct mod_setup_stream { + u8 standard; + u8 stream_format; + u8 rsvd[2]; + u32 symbol_rate; /* only used when Standard doesn't define a fixed symbol rate */ + u8 fft_size; /* 0 = 2K, 1 = 8K (2K yet supported) */ + u8 guard_interval; /* 0 = 1/32, 1 = 1/16, 2 = 1/8, 3 = 1/4 (DVB-T Encoding) */ +}; + +struct mod_setup_output { + u8 connector; /* 0 = OFF, 1 = F, 2 = SMA */ + u8 num_channels; /* max active channels, determines max power for each channel. */ + u8 unit; /* 0 = dBµV, 1 = dBm, */ + u8 rsvd; + s16 channel_power; +}; /********************************************************/ @@ -197,6 +251,12 @@ struct mci_command { u8 demod; u8 output; }; + struct { + u8 mod_command; + u8 mod_channel; + u8 mod_stream; + u8 mod_rsvd1; + }; }; union { u32 params[31]; @@ -307,27 +367,27 @@ struct mci_command { } get_iq_symbol; struct { - uint8_t flags; /* Bit 0 : 0 = VTM/SDR, 1 = SCAN, + u8 flags; /* Bit 0 : 0 = VTM/SDR, 1 = SCAN, Bit 1: 1 = Disable AGC, Bit 2: 1 = Set Gain. */ - uint8_t roll_off; - uint8_t rsvd1; - uint8_t rsvd2; - uint32_t frequency; - uint32_t symbol_rate; /* Only in VTM/SDR mode, SCAN Mode uses exactly 1550/24 MSymbols/s.*/ - uint8_t gain; /* Gain in 0.25 dB Steps */ + u8 roll_off; + u8 rsvd1; + u8 rsvd2; + u32 frequency; + u32 symbol_rate; /* Only in VTM/SDR mode, SCAN Mode uses exactly 1550/24 MSymbols/s.*/ + u8 gain; /* Gain in 0.25 dB Steps */ /* Frequency, symbolrate and gain can be schanged while running */ } sx8_start_iq; struct { - uint8_t flags; + u8 flags; /* Bit 0:1 Preamp Mode; 0 = Preamp AGC, 1 == Minimum (~ -17dB) , 2 = Medium, 3 = Maximum gain {~ 15dB} Bit 2: Bypass Input LNA (6 dB less gain) (Note this is after Preamp) Bit 4: Set RF Gain Bit 5: Freeze RF Gain (Turn AGC off at current gain, only when already enabled) Bit 7: Optimize RF Gain and freeze for FFT */ - uint8_t rf_gain; /* 0 .. 50 dB */ + u8 rf_gain; /* 0 .. 50 dB */ } sx8_input_enable; struct { @@ -344,6 +404,10 @@ struct mci_command { struct { u8 select; // 0 = Data PLP, 1 = Common PLP, only DVB-T2 and DVB-C2 } get_bb_header; + + struct mod_setup_channels mod_setup_channels[4]; + struct mod_setup_stream mod_setup_stream; + struct mod_setup_output mod_setup_output; }; }; @@ -800,7 +864,7 @@ int ddb_mci_get_info(struct mci *mci); int ddb_mci_get_strength(struct dvb_frontend *fe); void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p); int mci_init(struct ddb_link *link); -int mci_cmd_val(struct ddb_link *link, uint32_t cmd, uint32_t val); +int mci_cmd_val(struct ddb_link *link, u32 cmd, u32 val); extern struct mci_cfg ddb_max_sx8_cfg; extern struct mci_cfg ddb_max_m4_cfg; diff --git a/ddbridge/ddbridge-modulator.c b/ddbridge/ddbridge-modulator.c index c5a9b70..986cf2f 100644 --- a/ddbridge/ddbridge-modulator.c +++ b/ddbridge/ddbridge-modulator.c @@ -644,7 +644,6 @@ static int mod_set_sdr_attenuator(struct ddb *dev, u32 value) static int mod_set_sdr_gain(struct ddb *dev, u32 gain) { u32 control = ddbreadl(dev, SDR_CONTROL); - struct ddb_link *link = &dev->link[0]; if (control & 0x01000000) { if (gain > 511) @@ -659,8 +658,6 @@ static int mod_set_sdr_gain(struct ddb *dev, u32 gain) return -EINVAL; ddbwritel(dev, gain, SDR_GAIN_F); } - if (link->mci_ok) - mci_cmd_val(link, 0xc0, gain); return 0; } @@ -2032,6 +2029,9 @@ static int mod_init_sdr_iq(struct ddb *dev) ddbwritel(dev, 0x01, 0x240); + if (dev->link[0].ids.revision == 1) + return 0; + //mod3_set_base_frequency(dev, 602000000); dev->mod_base.frequency = 570000000; for (i = 0; i < streams; i++) { diff --git a/ddbridge/ddbridge.h b/ddbridge/ddbridge.h index 7002590..c986e6a 100644 --- a/ddbridge/ddbridge.h +++ b/ddbridge/ddbridge.h @@ -143,6 +143,7 @@ struct ddb_ids { u32 regmapid; u32 devid; u32 mac; + u8 revision; }; struct ddb_info {