14 -> TurboSight TBS 6920                                 [6920:8888]
  15 -> TeVii S470                                          [d470:9022]
  16 -> DVBWorld DVB-S2 2005                                [0001:2005]
+ 17 -> NetUP Dual DVB-S2 CI                                [1b55:2a2c]
 
        select DVB_LGDT330X if !DVB_FE_CUSTOMISE
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
        select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
+       select DVB_LNBP21 if !DVB_FE_CUSTOMIZE
        select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMIZE
        select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE
        select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
 
-cx23885-objs   := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o
+cx23885-objs   := cx23885-cards.o cx23885-video.o cx23885-vbi.o \
+                   cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \
+                   netup-init.o cimax2.o netup-eeprom.o
 
 obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
 
 
 
 #include "cx23885.h"
 #include "tuner-xc2028.h"
+#include "netup-init.h"
 
 /* ------------------------------------------------------------------ */
 /* board config info                                                  */
                .name           = "DVBWorld DVB-S2 2005",
                .portb          = CX23885_MPEG_DVB,
        },
+       [CX23885_BOARD_NETUP_DUAL_DVBS2_CI] = {
+               .cimax          = 1,
+               .name           = "NetUP Dual DVB-S2 CI",
+               .portb          = CX23885_MPEG_DVB,
+               .portc          = CX23885_MPEG_DVB,
+       },
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
                .subvendor = 0x0001,
                .subdevice = 0x2005,
                .card      = CX23885_BOARD_DVBWORLD_2005,
+       }, {
+               .subvendor = 0x1b55,
+               .subdevice = 0x2a2c,
+               .card      = CX23885_BOARD_NETUP_DUAL_DVBS2_CI,
        },
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
                cx_write(MC417_OEN, 0x00001000);
                cx_write(MC417_RWD, 0x00001800);
                break;
+       case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+               /* GPIO-0 INTA from CiMax1
+                  GPIO-1 INTB from CiMax2
+                  GPIO-2 reset chips
+                  GPIO-3 to GPIO-10 data/addr for CA
+                  GPIO-11 ~CS0 to CiMax1
+                  GPIO-12 ~CS1 to CiMax2
+                  GPIO-13 ADL0 load LSB addr
+                  GPIO-14 ADL1 load MSB addr
+                  GPIO-15 ~RDY from CiMax
+                  GPIO-17 ~RD to CiMax
+                  GPIO-18 ~WR to CiMax
+                */
+               cx_set(GP0_IO, 0x00040000); /* GPIO as out */
+               /* GPIO1 and GPIO2 as INTA and INTB from CiMaxes, reset low */
+               cx_clear(GP0_IO, 0x00030004);
+               mdelay(100);/* reset delay */
+               cx_set(GP0_IO, 0x00040004); /* GPIO as out, reset high */
+               cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */
+               /* GPIO-15 IN as ~ACK, rest as OUT */
+               cx_write(MC417_OEN, 0x00001000);
+               /* ~RD, ~WR high; ADL0, ADL1 low; ~CS0, ~CS1 high */
+               cx_write(MC417_RWD, 0x0000c300);
+               /* enable irq */
+               cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
+               break;
        }
 }
 
                ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
                ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
                break;
+       case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+               ts1->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+               ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+               ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+               ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+               ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+               ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+               break;
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
        case CX23885_BOARD_HAUPPAUGE_HVR1500:
        case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
        case CX23885_BOARD_HAUPPAUGE_HVR1700:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+       case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
                request_module("cx25840");
                break;
        }
+
+       /* AUX-PLL 27MHz CLK */
+       switch (dev->board) {
+       case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+               netup_initialize(dev);
+               break;
+       }
 }
 
 /* ------------------------------------------------------------------ */
 
 #include <asm/div64.h>
 
 #include "cx23885.h"
+#include "cimax2.h"
 
 MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
 MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
        dev->pci_bus  = dev->pci->bus->number;
        dev->pci_slot = PCI_SLOT(dev->pci->devfn);
        dev->pci_irqmask = 0x001f00;
+       if (cx23885_boards[dev->board].cimax > 0)
+               dev->pci_irqmask |= 0x01800000; /* for CiMaxes */
 
        /* External Master 1 Bus */
        dev->i2c_bus[0].nr = 0;
            (pci_status & PCI_MSK_VID_B) ||
            (pci_status & PCI_MSK_VID_A) ||
            (pci_status & PCI_MSK_AUD_INT) ||
-           (pci_status & PCI_MSK_AUD_EXT)) {
+           (pci_status & PCI_MSK_AUD_EXT) ||
+           (pci_status & PCI_MSK_GPIO0) ||
+           (pci_status & PCI_MSK_GPIO1)) {
 
                if (pci_status & PCI_MSK_RISC_RD)
                        dprintk(7, " (PCI_MSK_RISC_RD   0x%08x)\n",
                        dprintk(7, " (PCI_MSK_AUD_EXT   0x%08x)\n",
                                PCI_MSK_AUD_EXT);
 
+               if (pci_status & PCI_MSK_GPIO0)
+                       dprintk(7, " (PCI_MSK_GPIO0     0x%08x)\n",
+                               PCI_MSK_GPIO0);
+
+               if (pci_status & PCI_MSK_GPIO1)
+                       dprintk(7, " (PCI_MSK_GPIO1     0x%08x)\n",
+                               PCI_MSK_GPIO1);
        }
 
+       if ((pci_status & PCI_MSK_GPIO0) || (pci_status & PCI_MSK_GPIO1))
+               /* handled += cx23885_irq_gpio(dev, pci_status); */
+               handled += netup_ci_slot_status(dev, pci_status);
+
        if (ts1_status) {
                if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
                        handled += cx23885_irq_ts(ts1, ts1_status);
        }
 
        pci_set_drvdata(pci_dev, dev);
+       cx_set(PCI_INT_MSK, 0x01800000); /* for NetUP */
+
        return 0;
 
 fail_irq:
 
 #include "cx23885.h"
 #include <media/v4l2-common.h>
 
+#include "dvb_ca_en50221.h"
 #include "s5h1409.h"
 #include "s5h1411.h"
 #include "mt2131.h"
 #include "dib7000p.h"
 #include "dibx000_common.h"
 #include "zl10353.h"
+#include "stv0900.h"
+#include "stv6110.h"
+#include "lnbh24.h"
 #include "cx24116.h"
+#include "cimax2.h"
+#include "netup-eeprom.h"
+#include "netup-init.h"
 
 static unsigned int debug;
 
        .no_tuner      = 1,
 };
 
+static struct stv0900_config netup_stv0900_config = {
+       .demod_address = 0x68,
+       .xtal = 27000000,
+       .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
+       .diseqc_mode = 2,/* 2/3 PWM */
+       .path1_mode = 2,/*Serial continues clock */
+       .path2_mode = 2,/*Serial continues clock */
+       .tun1_maddress = 0,/* 0x60 */
+       .tun2_maddress = 3,/* 0x63 */
+       .tun1_adc = 1,/* 1 Vpp */
+       .tun2_adc = 1,/* 1 Vpp */
+};
+
+static struct stv6110_config netup_stv6110_tunerconfig_a = {
+       .i2c_address = 0x60,
+       .mclk = 27000000,
+       .iq_wiring = 0,
+};
+
+static struct stv6110_config netup_stv6110_tunerconfig_b = {
+       .i2c_address = 0x63,
+       .mclk = 27000000,
+       .iq_wiring = 1,
+};
+
 static int tbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
        struct cx23885_tsport *port = fe->dvb->priv;
        struct cx23885_dev *dev = port->dev;
        struct cx23885_i2c *i2c_bus = NULL;
        struct videobuf_dvb_frontend *fe0;
+       int ret;
 
        /* Get the first frontend */
        fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
                        &dvbworld_cx24116_config,
                        &i2c_bus->i2c_adap);
                break;
+       case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+               i2c_bus = &dev->i2c_bus[0];
+               switch (port->nr) {
+               /* port B */
+               case 1:
+                       fe0->dvb.frontend = dvb_attach(stv0900_attach,
+                                                       &netup_stv0900_config,
+                                                       &i2c_bus->i2c_adap, 0);
+                       if (fe0->dvb.frontend != NULL) {
+                               if (dvb_attach(stv6110_attach,
+                                               fe0->dvb.frontend,
+                                               &netup_stv6110_tunerconfig_a,
+                                               &i2c_bus->i2c_adap)) {
+                                       if (!dvb_attach(lnbh24_attach,
+                                                       fe0->dvb.frontend,
+                                                       &i2c_bus->i2c_adap,
+                                                       LNBH24_PCL, 0, 0x09))
+                                               printk(KERN_ERR
+                                                       "No LNBH24 found!\n");
+
+                               }
+                       }
+                       break;
+               /* port C */
+               case 2:
+                       fe0->dvb.frontend = dvb_attach(stv0900_attach,
+                                                       &netup_stv0900_config,
+                                                       &i2c_bus->i2c_adap, 1);
+                       if (fe0->dvb.frontend != NULL) {
+                               if (dvb_attach(stv6110_attach,
+                                               fe0->dvb.frontend,
+                                               &netup_stv6110_tunerconfig_b,
+                                               &i2c_bus->i2c_adap)) {
+                                       if (!dvb_attach(lnbh24_attach,
+                                                       fe0->dvb.frontend,
+                                                       &i2c_bus->i2c_adap,
+                                                       LNBH24_PCL, 0, 0x0a))
+                                               printk(KERN_ERR
+                                                       "No LNBH24 found!\n");
+
+                               }
+                       }
+                       break;
+               }
+               break;
        default:
                printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
                        " isn't supported yet\n",
                fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
 
        /* register everything */
-       return videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
+       ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
                &dev->pci->dev, adapter_nr, 0);
 
+       /* init CI & MAC */
+       switch (dev->board) {
+       case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: {
+               static struct netup_card_info cinfo;
+
+               netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
+               memcpy(port->frontends.adapter.proposed_mac,
+                               cinfo.port[port->nr - 1].mac, 6);
+               printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC="
+                       "%02X:%02X:%02X:%02X:%02X:%02X\n",
+                       port->nr,
+                       port->frontends.adapter.proposed_mac[0],
+                       port->frontends.adapter.proposed_mac[1],
+                       port->frontends.adapter.proposed_mac[2],
+                       port->frontends.adapter.proposed_mac[3],
+                       port->frontends.adapter.proposed_mac[4],
+                       port->frontends.adapter.proposed_mac[5]);
+
+               netup_ci_init(port);
+               break;
+               }
+       }
+
+       return ret;
 }
 
 int cx23885_dvb_register(struct cx23885_tsport *port)
        if (fe0->dvb.frontend)
                videobuf_dvb_unregister_bus(&port->frontends);
 
+       netup_ci_exit(port);
+
        return 0;
 }
 
 
 
 #define DEV_CNTRL2     0x00040000
 
+#define PCI_MSK_GPIO1   (1 << 24)
+#define PCI_MSK_GPIO0   (1 << 23)
 #define PCI_MSK_APB_DMA   (1 << 12)
 #define PCI_MSK_AL_WR     (1 << 11)
 #define PCI_MSK_AL_RD     (1 << 10)
 
 #define CX23885_BOARD_TBS_6920                 14
 #define CX23885_BOARD_TEVII_S470               15
 #define CX23885_BOARD_DVBWORLD_2005            16
+#define CX23885_BOARD_NETUP_DUAL_DVBS2_CI      17
 
 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
 #define CX23885_NORMS (\
         */
        u32                     clk_freq;
        struct cx23885_input    input[MAX_CX23885_INPUT];
+       int                     cimax; /* for NetUP */
 };
 
 struct cx23885_subid {
 
        /* Allow a single tsport to have multiple frontends */
        u32                        num_frontends;
+       void                       *port_priv;
 };
 
 struct cx23885_dev {