V4L/DVB (6021): cx88: Copy board information into card state
[deliverable/linux.git] / drivers / media / video / cx88 / cx88-core.c
index 4b655f2ef27880038222e9795302887571325086..ece788bd3d551477f5c5b3996034439ae7a5dddd 100644 (file)
@@ -5,6 +5,11 @@
  *
  * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
  *
+ * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *     - Multituner support
+ *     - video_ioctl2 conversion
+ *     - PAL/M fixes
+ *
  *  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
@@ -484,12 +489,12 @@ static char *cx88_pci_irqs[32] = {
 };
 
 void cx88_print_irqbits(char *name, char *tag, char **strings,
-                       u32 bits, u32 mask)
+                       int len, u32 bits, u32 mask)
 {
        unsigned int i;
 
        printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits);
-       for (i = 0; i < 32; i++) {
+       for (i = 0; i < len; i++) {
                if (!(bits & (1 << i)))
                        continue;
                if (strings[i])
@@ -515,8 +520,8 @@ int cx88_core_irq(struct cx88_core *core, u32 status)
        }
        if (!handled)
                cx88_print_irqbits(core->name, "irq pci",
-                                  cx88_pci_irqs, status,
-                                  core->pci_irqmask);
+                                  cx88_pci_irqs, ARRAY_SIZE(cx88_pci_irqs),
+                                  status, core->pci_irqmask);
        return handled;
 }
 
@@ -631,46 +636,55 @@ int cx88_reset(struct cx88_core *core)
 
 /* ------------------------------------------------------------------ */
 
-static unsigned int inline norm_swidth(struct cx88_tvnorm *norm)
+static unsigned int inline norm_swidth(v4l2_std_id norm)
 {
-       return (norm->id & V4L2_STD_625_50) ? 922 : 754;
+       return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
 }
 
-static unsigned int inline norm_hdelay(struct cx88_tvnorm *norm)
+static unsigned int inline norm_hdelay(v4l2_std_id norm)
 {
-       return (norm->id & V4L2_STD_625_50) ? 186 : 135;
+       return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
 }
 
-static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm)
+static unsigned int inline norm_vdelay(v4l2_std_id norm)
 {
-       return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;
+       return (norm & V4L2_STD_625_50) ? 0x24 : 0x18;
 }
 
-static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
+static unsigned int inline norm_fsc8(v4l2_std_id norm)
 {
-       static const unsigned int ntsc = 28636360;
-       static const unsigned int pal  = 35468950;
-       static const unsigned int palm  = 28604892;
+       if (norm & V4L2_STD_PAL_M)
+               return 28604892;      // 3.575611 MHz
+
+       if (norm & (V4L2_STD_PAL_Nc))
+               return 28656448;      // 3.582056 MHz
+
+       if (norm & V4L2_STD_NTSC) // All NTSC/M and variants
+               return 28636360;      // 3.57954545 MHz +/- 10 Hz
 
-       if (norm->id & V4L2_STD_PAL_M)
-               return palm;
+       /* SECAM have also different sub carrier for chroma,
+          but step_db and step_dr, at cx88_set_tvnorm already handles that.
 
-       return (norm->id & V4L2_STD_625_50) ? pal : ntsc;
+          The same FSC applies to PAL/BGDKIH, PAL/60, NTSC/4.43 and PAL/N
+        */
+
+       return 35468950;      // 4.43361875 MHz +/- 5 Hz
 }
 
-static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
+static unsigned int inline norm_htotal(v4l2_std_id norm)
 {
-       /* Should always be Line Draw Time / (4*FSC) */
 
-       if (norm->id & V4L2_STD_PAL_M)
-               return 909;
+       unsigned int fsc4=norm_fsc8(norm)/2;
 
-       return (norm->id & V4L2_STD_625_50) ? 1135 : 910;
+       /* returns 4*FSC / vtotal / frames per seconds */
+       return (norm & V4L2_STD_625_50) ?
+                               ((fsc4+312)/625+12)/25 :
+                               ((fsc4+262)/525*1001+15000)/30000;
 }
 
-static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
+static unsigned int inline norm_vbipack(v4l2_std_id norm)
 {
-       return (norm->id & V4L2_STD_625_50) ? 511 : 400;
+       return (norm & V4L2_STD_625_50) ? 511 : 400;
 }
 
 int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
@@ -683,7 +697,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
        dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
                V4L2_FIELD_HAS_TOP(field)    ? "T" : "",
                V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
-               core->tvnorm->name);
+               v4l2_norm_to_name(core->tvnorm));
        if (!V4L2_FIELD_HAS_BOTH(field))
                height *= 2;
 
@@ -692,7 +706,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
        value &= 0x3fe;
        cx_write(MO_HDELAY_EVEN,  value);
        cx_write(MO_HDELAY_ODD,   value);
-       dprintk(1,"set_scale: hdelay  0x%04x\n", value);
+       dprintk(1,"set_scale: hdelay  0x%04x (width %d)\n", value,swidth);
 
        value = (swidth * 4096 / width) - 4096;
        cx_write(MO_HSCALE_EVEN,  value);
@@ -720,11 +734,11 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
        // setup filters
        value = 0;
        value |= (1 << 19);        // CFILT (default)
-       if (core->tvnorm->id & V4L2_STD_SECAM) {
+       if (core->tvnorm & V4L2_STD_SECAM) {
                value |= (1 << 15);
                value |= (1 << 16);
        }
-       if (INPUT(core->input)->type == CX88_VMUX_SVIDEO)
+       if (INPUT(core->input).type == CX88_VMUX_SVIDEO)
                value |= (1 << 13) | (1 << 5);
        if (V4L2_FIELD_INTERLACED == field)
                value |= (1 << 3); // VINT (interlaced vertical scaling)
@@ -817,36 +831,36 @@ int cx88_stop_audio_dma(struct cx88_core *core)
 
 static int set_tvaudio(struct cx88_core *core)
 {
-       struct cx88_tvnorm *norm = core->tvnorm;
+       v4l2_std_id norm = core->tvnorm;
 
-       if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
+       if (CX88_VMUX_TELEVISION != INPUT(core->input).type)
                return 0;
 
-       if (V4L2_STD_PAL_BG & norm->id) {
+       if (V4L2_STD_PAL_BG & norm) {
                core->tvaudio = WW_BG;
 
-       } else if (V4L2_STD_PAL_DK & norm->id) {
+       } else if (V4L2_STD_PAL_DK & norm) {
                core->tvaudio = WW_DK;
 
-       } else if (V4L2_STD_PAL_I & norm->id) {
+       } else if (V4L2_STD_PAL_I & norm) {
                core->tvaudio = WW_I;
 
-       } else if (V4L2_STD_SECAM_L & norm->id) {
+       } else if (V4L2_STD_SECAM_L & norm) {
                core->tvaudio = WW_L;
 
-       } else if (V4L2_STD_SECAM_DK & norm->id) {
+       } else if (V4L2_STD_SECAM_DK & norm) {
                core->tvaudio = WW_DK;
 
-       } else if ((V4L2_STD_NTSC_M & norm->id) ||
-                  (V4L2_STD_PAL_M  & norm->id)) {
+       } else if ((V4L2_STD_NTSC_M & norm) ||
+                  (V4L2_STD_PAL_M  & norm)) {
                core->tvaudio = WW_BTSC;
 
-       } else if (V4L2_STD_NTSC_M_JP & norm->id) {
+       } else if (V4L2_STD_NTSC_M_JP & norm) {
                core->tvaudio = WW_EIAJ;
 
        } else {
                printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
-                      core->name, norm->name);
+                      core->name, v4l2_norm_to_name(core->tvnorm));
                core->tvaudio = 0;
                return 0;
        }
@@ -865,7 +879,7 @@ static int set_tvaudio(struct cx88_core *core)
 
 
 
-int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
+int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
 {
        u32 fsc8;
        u32 adc_clock;
@@ -873,6 +887,7 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
        u32 step_db,step_dr;
        u64 tmp64;
        u32 bdelay,agcdelay,htotal;
+       u32 cxiformat, cxoformat;
 
        core->tvnorm = norm;
        fsc8       = norm_fsc8(norm);
@@ -881,23 +896,51 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
        step_db    = fsc8;
        step_dr    = fsc8;
 
-       if (norm->id & V4L2_STD_SECAM) {
+       if (norm & V4L2_STD_NTSC_M_JP) {
+               cxiformat = VideoFormatNTSCJapan;
+               cxoformat = 0x181f0008;
+       } else if (norm & V4L2_STD_NTSC_443) {
+               cxiformat = VideoFormatNTSC443;
+               cxoformat = 0x181f0008;
+       } else if (norm & V4L2_STD_PAL_M) {
+               cxiformat = VideoFormatPALM;
+               cxoformat = 0x1c1f0008;
+       } else if (norm & V4L2_STD_PAL_N) {
+               cxiformat = VideoFormatPALN;
+               cxoformat = 0x1c1f0008;
+       } else if (norm & V4L2_STD_PAL_Nc) {
+               cxiformat = VideoFormatPALNC;
+               cxoformat = 0x1c1f0008;
+       } else if (norm & V4L2_STD_PAL_60) {
+               cxiformat = VideoFormatPAL60;
+               cxoformat = 0x181f0008;
+       } else if (norm & V4L2_STD_NTSC) {
+               cxiformat = VideoFormatNTSC;
+               cxoformat = 0x181f0008;
+       } else if (norm & V4L2_STD_SECAM) {
                step_db = 4250000 * 8;
                step_dr = 4406250 * 8;
+
+               cxiformat = VideoFormatSECAM;
+               cxoformat = 0x181f0008;
+       } else { /* PAL */
+               cxiformat = VideoFormatPAL;
+               cxoformat = 0x181f0008;
        }
 
        dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
-               norm->name, fsc8, adc_clock, vdec_clock, step_db, step_dr);
+               v4l2_norm_to_name(core->tvnorm), fsc8, adc_clock, vdec_clock,
+               step_db, step_dr);
        set_pll(core,2,vdec_clock);
 
        dprintk(1,"set_tvnorm: MO_INPUT_FORMAT  0x%08x [old=0x%08x]\n",
-               norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
-       cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);
+               cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
+       cx_andor(MO_INPUT_FORMAT, 0xf, cxiformat);
 
        // FIXME: as-is from DScaler
        dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
-               norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));
-       cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);
+               cxoformat, cx_read(MO_OUTPUT_FORMAT));
+       cx_write(MO_OUTPUT_FORMAT, cxoformat);
 
        // MO_SCONV_REG = adc clock / video dec clock * 2^17
        tmp64  = adc_clock * (u64)(1 << 17);
@@ -946,7 +989,7 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
        set_tvaudio(core);
 
        // tell i2c chips
-       cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
+       cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm);
 
        // done
        return 0;
@@ -1024,7 +1067,7 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
        vfd->dev     = &pci->dev;
        vfd->release = video_device_release;
        snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
-                core->name, type, cx88_boards[core->board].name);
+                core->name, type, core->board.name);
        return vfd;
 }
 
@@ -1034,8 +1077,11 @@ static int get_ressources(struct cx88_core *core, struct pci_dev *pci)
                               pci_resource_len(pci,0),
                               core->name))
                return 0;
-       printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
-              core->name,(unsigned long long)pci_resource_start(pci,0));
+       printk(KERN_ERR
+              "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n",
+              core->name, PCI_FUNC(pci->devfn),
+              (unsigned long long)pci_resource_start(pci, 0),
+              pci->subsystem_vendor, pci->subsystem_device);
        return -EBUSY;
 }
 
@@ -1072,12 +1118,6 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci)
        core->nr = cx88_devcount++;
        sprintf(core->name,"cx88[%d]",core->nr);
        if (0 != get_ressources(core,pci)) {
-               printk(KERN_ERR "CORE %s No more PCI ressources for "
-                       "subsystem: %04x:%04x, board: %s\n",
-                       core->name,pci->subsystem_vendor,
-                       pci->subsystem_device,
-                       cx88_boards[core->board].name);
-
                cx88_devcount--;
                goto fail_free;
        }
@@ -1090,39 +1130,34 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci)
        core->bmmio = (u8 __iomem *)core->lmmio;
 
        /* board config */
-       core->board = UNSET;
+       core->boardnr = UNSET;
        if (card[core->nr] < cx88_bcount)
-               core->board = card[core->nr];
-       for (i = 0; UNSET == core->board  &&  i < cx88_idcount; i++)
+               core->boardnr = card[core->nr];
+       for (i = 0; UNSET == core->boardnr  &&  i < cx88_idcount; i++)
                if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
                    pci->subsystem_device == cx88_subids[i].subdevice)
-                       core->board = cx88_subids[i].card;
-       if (UNSET == core->board) {
-               core->board = CX88_BOARD_UNKNOWN;
+                       core->boardnr = cx88_subids[i].card;
+       if (UNSET == core->boardnr) {
+               core->boardnr = CX88_BOARD_UNKNOWN;
                cx88_card_list(core,pci);
        }
+
+       memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board));
+
        printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
                core->name,pci->subsystem_vendor,
-               pci->subsystem_device,cx88_boards[core->board].name,
-               core->board, card[core->nr] == core->board ?
+               pci->subsystem_device, core->board.name,
+               core->boardnr, card[core->nr] == core->boardnr ?
                "insmod option" : "autodetected");
 
-       core->tuner_type = tuner[core->nr];
-       core->radio_type = radio[core->nr];
-       if (UNSET == core->tuner_type)
-               core->tuner_type = cx88_boards[core->board].tuner_type;
-       if (UNSET == core->radio_type)
-               core->radio_type = cx88_boards[core->board].radio_type;
-       if (!core->tuner_addr)
-               core->tuner_addr = cx88_boards[core->board].tuner_addr;
-       if (!core->radio_addr)
-               core->radio_addr = cx88_boards[core->board].radio_addr;
+       if (tuner[core->nr] != UNSET)
+               core->board.tuner_type = tuner[core->nr];
+       if (radio[core->nr] != UNSET)
+               core->board.radio_type = radio[core->nr];
 
        printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
-               core->tuner_type, core->tuner_addr<<1,
-               core->radio_type, core->radio_addr<<1);
-
-       core->tda9887_conf = cx88_boards[core->board].tda9887_conf;
+               core->board.tuner_type, core->board.tuner_addr<<1,
+               core->board.radio_type, core->board.radio_addr<<1);
 
        /* init hardware */
        cx88_reset(core);
@@ -1153,7 +1188,7 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
        mutex_lock(&devlist);
        cx88_ir_fini(core);
        if (0 == core->i2c_rc)
-               i2c_bit_del_bus(&core->i2c_adap);
+               i2c_del_adapter(&core->i2c_adap);
        list_del(&core->devlist);
        iounmap(core->lmmio);
        cx88_devcount--;
This page took 0.051382 seconds and 5 git commands to generate.