diff -u --new-file org/diseqc.c new/diseqc.c
--- org/diseqc.c	2009-10-09 01:41:41.000000000 +0200
+++ new/diseqc.c	2011-03-07 21:08:00.000000000 +0100
@@ -19,6 +19,7 @@
   commands = NULL;
   parsing = false;
   numCodes = 0;
+  unicable = -1;
 }
 
 cDiseqc::~cDiseqc()
@@ -73,15 +74,17 @@
 {
   char *e = strchr(s, ']');
   if (e) {
-     numCodes = 0;
+     int num = 0;
      char *t = s;
      char *p = s;
      while (t < e) {
-           if (numCodes < MaxDiseqcCodes) {
+           if (num < MaxDiseqcCodes) {
               errno = 0;
               int n = strtol(t, &p, 16);
               if (!errno && p != t && 0 <= n && n <= 255) {
-                 codes[numCodes++] = n;
+                 if (parsing)
+			codes[num] = uchar(n);
+		   ++num;
                  t = skipspace(p);
                  }
               else {
@@ -94,6 +97,8 @@
               return NULL;
               }
            }
+     if (parsing)
+	numCodes = num;
      return e + 1;
      }
   else
@@ -101,6 +106,46 @@
   return NULL;
 }
 
+char *cDiseqc::Unicable(char *s)
+{
+  char *p = NULL;
+  errno = 0;
+  int n = strtol(s, &p, 10);
+  if (!errno && p != s && n >= 0 && n < 8) {
+     if (parsing)
+        unicable = n;
+     return p;
+     }
+  esyslog("ERROR: invalid unicable sat in '%s'", s - 1);
+  return NULL;
+}
+
+unsigned int cDiseqc::UnicableFreq(unsigned int frequency, int satcr, unsigned int bpf)
+{
+  unsigned int t = frequency == 0 ? 0 : (frequency + bpf + 2) / 4 - 350;
+  if (t < 1024 && satcr >= 0 && satcr < 8)
+  {
+    codes[3] = t >> 8 | (t == 0 ? 0 : unicable << 2) | satcr << 5;
+    codes[4] = t;
+    return (t + 350) * 4 - frequency;
+  }
+  
+  return 0;
+}
+
+void cDiseqc::UnicablePin(int pin)
+{
+  if (pin >= 0 && pin <= 255) {
+    numCodes = 6;
+    codes[2] = 0x5c;
+    codes[5] = pin;
+    }
+  else {
+    numCodes = 5;
+    codes[2] = 0x5a;
+    }
+}
+
 cDiseqc::eDiseqcActions cDiseqc::Execute(char **CurrentAction)
 {
   if (!*CurrentAction)
@@ -119,6 +164,7 @@
 #endif /* GOTOX */
           case 'W': *CurrentAction = Wait(*CurrentAction); break;
           case '[': *CurrentAction = Codes(*CurrentAction); return *CurrentAction ? daCodes : daNone;
+	   case 'U': *CurrentAction = Unicable(*CurrentAction); return *CurrentAction ? daUnicable : daNone;
           default: return daNone;
           }
         }
@@ -137,3 +183,45 @@
       }
   return NULL;
 }
+
+// --- cUnicable --------------------------------------------------------------
+
+cUnicable::cUnicable()
+{
+  satcr = -1;
+  bpf = 0;
+  pin = -1;
+  unused = true;
+}
+
+bool cUnicable::Parse(const char *s)
+{
+  bool result = false;
+  int fields = sscanf(s, "%d %u %d", &satcr, &bpf, &pin);
+  if (fields >= 2) {
+     if (satcr >= 0 && satcr < 8)
+        result = true;
+     else
+        esyslog("Error: invalid unicable channel '%d'", satcr);
+     if (result && fields == 3 && (pin < 0 || pin > 255)) {
+        esyslog("Error: invalid unicable pin '%d'", pin);
+        result = false;
+        }
+     }
+  return result;
+}
+
+// --- cUnicables --------------------------------------------------------------
+
+cUnicables Unicables;
+
+cUnicable *cUnicables::GetUnused()
+{
+  for (cUnicable *p = First(); p; p = Next(p)) {
+      if (p->Unused()) {
+        p->Use();
+        return p;
+        }
+      }
+  return NULL;
+}
diff -u --new-file org/diseqc.conf new/diseqc.conf
--- org/diseqc.conf	2009-10-09 01:41:41.000000000 +0200
+++ new/diseqc.conf	2011-03-07 21:18:33.000000000 +0100
@@ -18,6 +18,7 @@
 #   V         voltage high (18V)
 #   A         mini A
 #   B         mini B
+#   Un		unicable code sequence for bank n follows
 #   Wnn       wait nn milliseconds (nn may be any positive integer number)
 #   [xx ...]  hex code sequence (max. 6)
 #
@@ -71,3 +72,16 @@
 # S19.2E  99999 H 10560 t v
 # S19.2E  12110 V 11080 t v
 # S19.2E  99999 V 10720 t v
+#
+# Unicable
+#
+# S19.2E  11700 V  9750  t V U0 W10 [E0 10 5A 00 00] W10 v
+# S19.2E  99999 V 10600  t V U1 W10 [E0 10 5A 00 00] W10 v
+# S19.2E  11700 H  9750  t V U2 W10 [E0 10 5A 00 00] W10 v
+# S19.2E  99999 H 10600  t V U3 W10 [E0 10 5A 00 00] W10 v
+#
+# S13.0E  11700 V  9750  t V U4 W10 [E0 10 5A 00 00] W10 v
+# S13.0E  99999 V 10600  t V U5 W10 [E0 10 5A 00 00] W10 v
+# S13.0E  11700 H  9750  t V U6 W10 [E0 10 5A 00 00] W10 v
+# S13.0E  99999 H 10600  t V U7 W10 [E0 10 5A 00 00] W10 v
+
diff -u --new-file org/diseqc.h new/diseqc.h
--- org/diseqc.h	2009-10-09 01:41:41.000000000 +0200
+++ new/diseqc.h	2011-03-07 21:14:54.000000000 +0100
@@ -26,6 +26,7 @@
     daGotoX,
 #endif /* GOTOX */
     daCodes,
+    daUnicable,
     };
   enum { MaxDiseqcCodes = 6 };
 private:
@@ -34,11 +35,13 @@
   char polarization;
   int lof;
   char *commands;
+  int unicable;
   bool parsing;
   uchar codes[MaxDiseqcCodes];
   int numCodes;
   char *Wait(char *s);
   char *Codes(char *s);
+  char *Unicable(char *s);
 public:
   cDiseqc(void);
   ~cDiseqc();
@@ -57,6 +60,9 @@
   int Lof(void) const { return lof; }
   const char *Commands(void) const { return commands; }
   uchar *Codes(int &NumCodes) { NumCodes = numCodes; return numCodes ? codes : NULL; }
+  bool Unicable() const { return unicable >= 0; }
+  unsigned int UnicableFreq(unsigned int frequency, int satcr, unsigned int bpf);
+  void UnicablePin(int pin);
   };
 
 class cDiseqcs : public cConfig<cDiseqc> {
@@ -66,4 +72,27 @@
 
 extern cDiseqcs Diseqcs;
 
+class cUnicable : public cListObject {
+private:
+  int satcr;
+  unsigned int bpf;
+  int pin;
+  bool unused;
+public:
+  cUnicable();
+  bool Parse(const char *s);
+  int Satcr() const { return satcr; }
+  unsigned int Bpf() const { return bpf; }
+  int Pin() const { return pin; }
+  bool Unused() const { return unused; }
+  void Use() { unused = false; }
+  };
+
+class cUnicables : public cConfig<cUnicable> {
+public:
+  cUnicable *GetUnused();
+  };
+
+extern cUnicables Unicables;
+
 #endif //__DISEQC_H
diff -u --new-file org/dvbdevice.c new/dvbdevice.c
--- org/dvbdevice.c	2009-10-09 01:41:41.000000000 +0200
+++ new/dvbdevice.c	2011-03-07 22:27:38.000000000 +0100
@@ -84,7 +84,8 @@
   time_t lastTimeoutReport;
   fe_delivery_system frontendType;
   cChannel channel;
-  const char *diseqcCommands;
+  cUnicable *unicable;
+  cDiseqc *diseqcLast;
   eTunerStatus tunerStatus;
   cMutex mutex;
   cCondVar locked;
@@ -93,6 +94,7 @@
   dvb_diseqc_master_cmd diseqc_cmd;
 #endif /* ROTOR */
   bool GetFrontendStatus(fe_status_t &Status, int TimeoutMs = 0);
+  void ExecuteDiseqc(cDiseqc *diseqc, unsigned int &frequency);
   bool SetFrontend(void);
   virtual void Action(void);
 public:
@@ -104,6 +106,9 @@
   bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd);
 #endif /* ROTOR */
   bool Locked(int TimeoutMs = 0);
+  int UnicableSatcr() const { return unicable ? unicable->Satcr() : -1; }
+  int UnicableBpf() const { return unicable ? unicable->Bpf() : 0; }
+  int UnicablePin() const { return unicable ? unicable->Pin() : -1; }
   };
 
 cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_delivery_system FrontendType)
@@ -117,10 +122,13 @@
   tuneTimeout = 0;
   lockTimeout = 0;
   lastTimeoutReport = 0;
-  diseqcCommands = NULL;
+  unicable = NULL;
+  diseqcLast = NULL;
   tunerStatus = tsIdle;
-  if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2)
+  if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) {
      CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power
+     unicable = Unicables.GetUnused();
+     }
   SetDescription("tuner on device %d", cardIndex + 1);
   Start();
 }
@@ -131,6 +139,10 @@
   newSet.Broadcast();
   locked.Broadcast();
   Cancel(3);
+  if (diseqcLast && diseqcLast->Unicable()) {
+    unsigned int frequency = 0;
+    ExecuteDiseqc(diseqcLast, frequency);
+    }
 }
 
 bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
@@ -217,6 +229,43 @@
   return f;
 }
 
+void cDvbTuner::ExecuteDiseqc(cDiseqc *diseqc, unsigned int &frequency)
+{
+  cDiseqc::eDiseqcActions da;
+  for (char *CurrentAction = NULL; (da = diseqc->Execute(&CurrentAction)) != cDiseqc::daNone; ) {
+    switch (da) {
+      case cDiseqc::daNone:      break;
+      case cDiseqc::daToneOff:   CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); break;
+      case cDiseqc::daToneOn:    CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_ON)); break;
+      case cDiseqc::daVoltage13: CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); break;
+      case cDiseqc::daVoltage18: CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_18)); break;
+      case cDiseqc::daMiniA:     CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_A)); break;
+      case cDiseqc::daMiniB:     CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_B)); break;
+      case cDiseqc::daCodes: {
+           int n = 0;
+           uchar *codes = diseqc->Codes(n);
+           if (codes) {
+             struct dvb_diseqc_master_cmd cmd;
+             memcpy(cmd.msg, codes, min(n, int(sizeof(cmd.msg))));
+             cmd.msg_len = n;
+             CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd));
+             }
+           }
+           break;
+      case cDiseqc::daUnicable: {
+           frequency = diseqc->UnicableFreq(frequency, UnicableSatcr(), UnicableBpf());
+           diseqc->UnicablePin(UnicablePin());
+           if (frequency == 0) {
+             CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13));
+             esyslog("ERROR: unable to setup unicable frequency for channel %d (f=%u, s=%d, b=%d)", channel.Number(), frequency, UnicableSatcr(), UnicableBpf());
+             }
+           }
+           break; 
+      default: esyslog("ERROR: unknown diseqc command %d", da);
+      }
+    }
+}
+
 #ifdef USE_GOTOX
 void HandleGotox(int fd_frontend, int new_source)
 {
@@ -325,39 +374,15 @@
      if (Setup.DiSEqC) {
         cDiseqc *diseqc = Diseqcs.Get(channel.Source(), channel.Frequency(), channel.Polarization());
         if (diseqc) {
-           if (diseqc->Commands() && (!diseqcCommands || strcmp(diseqcCommands, diseqc->Commands()) != 0)) {
-              cDiseqc::eDiseqcActions da;
-              for (char *CurrentAction = NULL; (da = diseqc->Execute(&CurrentAction)) != cDiseqc::daNone; ) {
-                  switch (da) {
-                    case cDiseqc::daNone:      break;
-                    case cDiseqc::daToneOff:   CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); break;
-                    case cDiseqc::daToneOn:    CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_ON)); break;
-                    case cDiseqc::daVoltage13: CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); break;
-                    case cDiseqc::daVoltage18: CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_18)); break;
-                    case cDiseqc::daMiniA:     CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_A)); break;
-                    case cDiseqc::daMiniB:     CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_B)); break;
-#ifdef USE_GOTOX
-                    case cDiseqc::daGotoX:     HandleGotox(fd_frontend, channel.Source()); break;
-#endif /* GOTOX */
-                    case cDiseqc::daCodes: {
-                         int n = 0;
-                         uchar *codes = diseqc->Codes(n);
-                         if (codes) {
-                            struct dvb_diseqc_master_cmd cmd;
-                            memcpy(cmd.msg, codes, min(n, int(sizeof(cmd.msg))));
-                            cmd.msg_len = n;
-                            CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd));
-                            }
-                         }
-                         break;
-                    }
-                  }
-              diseqcCommands = diseqc->Commands();
-#ifdef USE_DVBSETUP
-              isyslog("Sent DISEQC command: %s", diseqcCommands);
-#endif /* DVBSETUP */
-              }
+           
            frequency -= diseqc->Lof();
+           if (diseqc->Commands() && (!diseqcLast || strcmp(diseqcLast->Commands(), diseqc->Commands()) != 0 || diseqc->Unicable())) {
+              ExecuteDiseqc(diseqc, frequency);
+              if (frequency == 0) {
+                 return false;
+                 }
+              diseqcLast = diseqc;
+              }
            }
         else {
            esyslog("ERROR: no DiSEqC parameters found for channel %d", channel.Number());
@@ -489,7 +514,7 @@
           case tsTuned:
                if (Timer.TimedOut()) {
                   tunerStatus = tsSet;
-                  diseqcCommands = NULL;
+                  diseqcLast = NULL;
                   if (time(NULL) - lastTimeoutReport > 60) { // let's not get too many of these
                      isyslog("frontend %d timed out while tuning to channel %d, tp %d", cardIndex, channel.Number(), channel.Transponder());
                      lastTimeoutReport = time(NULL);
@@ -499,7 +524,7 @@
           case tsLocked:
                if (Status & FE_REINIT) {
                   tunerStatus = tsSet;
-                  diseqcCommands = NULL;
+                  diseqcLast = NULL;
                   isyslog("frontend %d was reinitialized", cardIndex);
                   lastTimeoutReport = 0;
                   continue;
diff -u --new-file org/vdr.c new/vdr.c
--- org/vdr.c	2009-11-12 20:05:22.000000000 +0100
+++ new/vdr.c	2011-03-07 21:49:14.000000000 +0100
@@ -830,7 +830,8 @@
   Setup.Load(AddDirectory(ConfigDirectory, "setup.conf"));
   if (!(Sources.Load(AddDirectory(ConfigDirectory, "sources.conf"), true, true) &&
         Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC) &&
-        Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true) &&
+        Unicables.Load(AddDirectory(ConfigDirectory, "unicable.conf"), true) &&
+	 Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true) &&
         Timers.Load(AddDirectory(ConfigDirectory, "timers.conf")) &&
 #ifdef USE_CMDRECCMDI18N
         LoadCommandsI18n(Commands,AddDirectory(ConfigDirectory, "commands.conf"), true) &&
