Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *
0004  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
0005  *
0006  * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
0007  *
0008  * Portions Copyright (c) 2001 Matrox Graphics Inc.
0009  *
0010  * Version: 1.65 2002/08/14
0011  *
0012  * See matroxfb_base.c for contributors.
0013  *
0014  */
0015 
0016 #include "matroxfb_base.h"
0017 #include "matroxfb_misc.h"
0018 #include "matroxfb_DAC1064.h"
0019 #include "g450_pll.h"
0020 #include <linux/matroxfb.h>
0021 #include <asm/div64.h>
0022 
0023 #include "matroxfb_g450.h"
0024 
0025 /* Definition of the various controls */
0026 struct mctl {
0027     struct v4l2_queryctrl desc;
0028     size_t control;
0029 };
0030 
0031 #define BLMIN   0xF3
0032 #define WLMAX   0x3FF
0033 
0034 static const struct mctl g450_controls[] =
0035 {   { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER, 
0036       "brightness",
0037       0, WLMAX-BLMIN, 1, 370-BLMIN, 
0038       0,
0039     }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
0040     { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER, 
0041       "contrast",
0042       0, 1023, 1, 127, 
0043       0,
0044     }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
0045     { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
0046       "saturation",
0047       0, 255, 1, 165, 
0048       0,
0049     }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
0050     { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
0051       "hue",
0052       0, 255, 1, 0, 
0053       0,
0054     }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
0055     { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN,
0056       "test output",
0057       0, 1, 1, 0, 
0058       0,
0059     }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
0060 };
0061 
0062 #define G450CTRLS ARRAY_SIZE(g450_controls)
0063 
0064 /* Return: positive number: id found
0065            -EINVAL:         id not found, return failure
0066        -ENOENT:         id not found, create fake disabled control */
0067 static int get_ctrl_id(__u32 v4l2_id) {
0068     int i;
0069 
0070     for (i = 0; i < G450CTRLS; i++) {
0071         if (v4l2_id < g450_controls[i].desc.id) {
0072             if (g450_controls[i].desc.id == 0x08000000) {
0073                 return -EINVAL;
0074             }
0075             return -ENOENT;
0076         }
0077         if (v4l2_id == g450_controls[i].desc.id) {
0078             return i;
0079         }
0080     }
0081     return -EINVAL;
0082 }
0083 
0084 static inline int *get_ctrl_ptr(struct matrox_fb_info *minfo, unsigned int idx)
0085 {
0086     return (int*)((char*)minfo + g450_controls[idx].control);
0087 }
0088 
0089 static void tvo_fill_defaults(struct matrox_fb_info *minfo)
0090 {
0091     unsigned int i;
0092     
0093     for (i = 0; i < G450CTRLS; i++) {
0094         *get_ctrl_ptr(minfo, i) = g450_controls[i].desc.default_value;
0095     }
0096 }
0097 
0098 static int cve2_get_reg(struct matrox_fb_info *minfo, int reg)
0099 {
0100     unsigned long flags;
0101     int val;
0102     
0103     matroxfb_DAC_lock_irqsave(flags);
0104     matroxfb_DAC_out(minfo, 0x87, reg);
0105     val = matroxfb_DAC_in(minfo, 0x88);
0106     matroxfb_DAC_unlock_irqrestore(flags);
0107     return val;
0108 }
0109 
0110 static void cve2_set_reg(struct matrox_fb_info *minfo, int reg, int val)
0111 {
0112     unsigned long flags;
0113 
0114     matroxfb_DAC_lock_irqsave(flags);
0115     matroxfb_DAC_out(minfo, 0x87, reg);
0116     matroxfb_DAC_out(minfo, 0x88, val);
0117     matroxfb_DAC_unlock_irqrestore(flags);
0118 }
0119 
0120 static void cve2_set_reg10(struct matrox_fb_info *minfo, int reg, int val)
0121 {
0122     unsigned long flags;
0123 
0124     matroxfb_DAC_lock_irqsave(flags);
0125     matroxfb_DAC_out(minfo, 0x87, reg);
0126     matroxfb_DAC_out(minfo, 0x88, val >> 2);
0127     matroxfb_DAC_out(minfo, 0x87, reg + 1);
0128     matroxfb_DAC_out(minfo, 0x88, val & 3);
0129     matroxfb_DAC_unlock_irqrestore(flags);
0130 }
0131 
0132 static void g450_compute_bwlevel(const struct matrox_fb_info *minfo, int *bl,
0133                  int *wl)
0134 {
0135     const int b = minfo->altout.tvo_params.brightness + BLMIN;
0136     const int c = minfo->altout.tvo_params.contrast;
0137 
0138     *bl = max(b - c, BLMIN);
0139     *wl = min(b + c, WLMAX);
0140 }
0141 
0142 static int g450_query_ctrl(void* md, struct v4l2_queryctrl *p) {
0143     int i;
0144     
0145     i = get_ctrl_id(p->id);
0146     if (i >= 0) {
0147         *p = g450_controls[i].desc;
0148         return 0;
0149     }
0150     if (i == -ENOENT) {
0151         static const struct v4l2_queryctrl disctrl = 
0152             { .flags = V4L2_CTRL_FLAG_DISABLED };
0153             
0154         i = p->id;
0155         *p = disctrl;
0156         p->id = i;
0157         sprintf(p->name, "Ctrl #%08X", i);
0158         return 0;
0159     }
0160     return -EINVAL;
0161 }
0162 
0163 static int g450_set_ctrl(void* md, struct v4l2_control *p) {
0164     int i;
0165     struct matrox_fb_info *minfo = md;
0166     
0167     i = get_ctrl_id(p->id);
0168     if (i < 0) return -EINVAL;
0169 
0170     /*
0171      * Check if changed.
0172      */
0173     if (p->value == *get_ctrl_ptr(minfo, i)) return 0;
0174 
0175     /*
0176      * Check limits.
0177      */
0178     if (p->value > g450_controls[i].desc.maximum) return -EINVAL;
0179     if (p->value < g450_controls[i].desc.minimum) return -EINVAL;
0180 
0181     /*
0182      * Store new value.
0183      */
0184     *get_ctrl_ptr(minfo, i) = p->value;
0185 
0186     switch (p->id) {
0187         case V4L2_CID_BRIGHTNESS:
0188         case V4L2_CID_CONTRAST:
0189             {
0190                 int blacklevel, whitelevel;
0191                 g450_compute_bwlevel(minfo, &blacklevel, &whitelevel);
0192                 cve2_set_reg10(minfo, 0x0e, blacklevel);
0193                 cve2_set_reg10(minfo, 0x1e, whitelevel);
0194             }
0195             break;
0196         case V4L2_CID_SATURATION:
0197             cve2_set_reg(minfo, 0x20, p->value);
0198             cve2_set_reg(minfo, 0x22, p->value);
0199             break;
0200         case V4L2_CID_HUE:
0201             cve2_set_reg(minfo, 0x25, p->value);
0202             break;
0203         case MATROXFB_CID_TESTOUT:
0204             {
0205                 unsigned char val = cve2_get_reg(minfo, 0x05);
0206                 if (p->value) val |=  0x02;
0207                 else          val &= ~0x02;
0208                 cve2_set_reg(minfo, 0x05, val);
0209             }
0210             break;
0211     }
0212     
0213 
0214     return 0;
0215 }
0216 
0217 static int g450_get_ctrl(void* md, struct v4l2_control *p) {
0218     int i;
0219     struct matrox_fb_info *minfo = md;
0220     
0221     i = get_ctrl_id(p->id);
0222     if (i < 0) return -EINVAL;
0223     p->value = *get_ctrl_ptr(minfo, i);
0224     return 0;
0225 }
0226 
0227 struct output_desc {
0228     unsigned int    h_vis;
0229     unsigned int    h_f_porch;
0230     unsigned int    h_sync;
0231     unsigned int    h_b_porch;
0232     unsigned long long int  chromasc;
0233     unsigned int    burst;
0234     unsigned int    v_total;
0235 };
0236 
0237 static void computeRegs(struct matrox_fb_info *minfo, struct mavenregs *r,
0238             struct my_timming *mt, const struct output_desc *outd)
0239 {
0240     u_int32_t chromasc;
0241     u_int32_t hlen;
0242     u_int32_t hsl;
0243     u_int32_t hbp;
0244     u_int32_t hfp;
0245     u_int32_t hvis;
0246     unsigned int pixclock;
0247     unsigned long long piic;
0248     int mnp;
0249     int over;
0250     
0251     r->regs[0x80] = 0x03;   /* | 0x40 for SCART */
0252 
0253     hvis = ((mt->HDisplay << 1) + 3) & ~3;
0254     
0255     if (hvis >= 2048) {
0256         hvis = 2044;
0257     }
0258     
0259     piic = 1000000000ULL * hvis;
0260     do_div(piic, outd->h_vis);
0261 
0262     dprintk(KERN_DEBUG "Want %u kHz pixclock\n", (unsigned int)piic);
0263     
0264     mnp = matroxfb_g450_setclk(minfo, piic, M_VIDEO_PLL);
0265     
0266     mt->mnp = mnp;
0267     mt->pixclock = g450_mnp2f(minfo, mnp);
0268 
0269     dprintk(KERN_DEBUG "MNP=%08X\n", mnp);
0270 
0271     pixclock = 1000000000U / mt->pixclock;
0272 
0273     dprintk(KERN_DEBUG "Got %u ps pixclock\n", pixclock);
0274 
0275     piic = outd->chromasc;
0276     do_div(piic, mt->pixclock);
0277     chromasc = piic;
0278     
0279     dprintk(KERN_DEBUG "Chroma is %08X\n", chromasc);
0280 
0281     r->regs[0] = piic >> 24;
0282     r->regs[1] = piic >> 16;
0283     r->regs[2] = piic >>  8;
0284     r->regs[3] = piic >>  0;
0285     hbp = (((outd->h_b_porch + pixclock) / pixclock)) & ~1;
0286     hfp = (((outd->h_f_porch + pixclock) / pixclock)) & ~1;
0287     hsl = (((outd->h_sync + pixclock) / pixclock)) & ~1;
0288     hlen = hvis + hfp + hsl + hbp;
0289     over = hlen & 0x0F;
0290     
0291     dprintk(KERN_DEBUG "WL: vis=%u, hf=%u, hs=%u, hb=%u, total=%u\n", hvis, hfp, hsl, hbp, hlen);
0292 
0293     if (over) {
0294         hfp -= over;
0295         hlen -= over;
0296         if (over <= 2) {
0297         } else if (over < 10) {
0298             hfp += 4;
0299             hlen += 4;
0300         } else {
0301             hfp += 16;
0302             hlen += 16;
0303         }
0304     }
0305 
0306     /* maybe cve2 has requirement 800 < hlen < 1184 */
0307     r->regs[0x08] = hsl;
0308     r->regs[0x09] = (outd->burst + pixclock - 1) / pixclock;    /* burst length */
0309     r->regs[0x0A] = hbp;
0310     r->regs[0x2C] = hfp;
0311     r->regs[0x31] = hvis / 8;
0312     r->regs[0x32] = hvis & 7;
0313     
0314     dprintk(KERN_DEBUG "PG: vis=%04X, hf=%02X, hs=%02X, hb=%02X, total=%04X\n", hvis, hfp, hsl, hbp, hlen);
0315 
0316     r->regs[0x84] = 1;  /* x sync point */
0317     r->regs[0x85] = 0;
0318     hvis = hvis >> 1;
0319     hlen = hlen >> 1;
0320     
0321     dprintk(KERN_DEBUG "hlen=%u hvis=%u\n", hlen, hvis);
0322 
0323     mt->interlaced = 1;
0324 
0325     mt->HDisplay = hvis & ~7;
0326     mt->HSyncStart = mt->HDisplay + 8;
0327     mt->HSyncEnd = (hlen & ~7) - 8;
0328     mt->HTotal = hlen;
0329 
0330     {
0331         int upper;
0332         unsigned int vtotal;
0333         unsigned int vsyncend;
0334         unsigned int vdisplay;
0335         
0336         vtotal = mt->VTotal;
0337         vsyncend = mt->VSyncEnd;
0338         vdisplay = mt->VDisplay;
0339         if (vtotal < outd->v_total) {
0340             unsigned int yovr = outd->v_total - vtotal;
0341             
0342             vsyncend += yovr >> 1;
0343         } else if (vtotal > outd->v_total) {
0344             vdisplay = outd->v_total - 4;
0345             vsyncend = outd->v_total;
0346         }
0347         upper = (outd->v_total - vsyncend) >> 1;    /* in field lines */
0348         r->regs[0x17] = outd->v_total / 4;
0349         r->regs[0x18] = outd->v_total & 3;
0350         r->regs[0x33] = upper - 1;  /* upper blanking */
0351         r->regs[0x82] = upper;      /* y sync point */
0352         r->regs[0x83] = upper >> 8;
0353         
0354         mt->VDisplay = vdisplay;
0355         mt->VSyncStart = outd->v_total - 2;
0356         mt->VSyncEnd = outd->v_total;
0357         mt->VTotal = outd->v_total;
0358     }
0359 }
0360 
0361 static void cve2_init_TVdata(int norm, struct mavenregs* data, const struct output_desc** outd) {
0362     static const struct output_desc paloutd = {
0363         .h_vis     = 52148148,  // ps
0364         .h_f_porch =  1407407,  // ps
0365         .h_sync    =  4666667,  // ps
0366         .h_b_porch =  5777778,  // ps
0367         .chromasc  = 19042247534182ULL, // 4433618.750 Hz
0368         .burst     =  2518518,  // ps
0369         .v_total   =      625,
0370     };
0371     static const struct output_desc ntscoutd = {
0372         .h_vis     = 52888889,  // ps
0373         .h_f_porch =  1333333,  // ps
0374         .h_sync    =  4666667,  // ps
0375         .h_b_porch =  4666667,  // ps
0376         .chromasc  = 15374030659475ULL, // 3579545.454 Hz
0377         .burst     =  2418418,  // ps
0378         .v_total   =      525,  // lines
0379     };
0380 
0381     static const struct mavenregs palregs = { {
0382         0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
0383         0x00,
0384         0x00,   /* test */
0385         0xF9,   /* modified by code (F9 written...) */
0386         0x00,   /* ? not written */
0387         0x7E,   /* 08 */
0388         0x44,   /* 09 */
0389         0x9C,   /* 0A */
0390         0x2E,   /* 0B */
0391         0x21,   /* 0C */
0392         0x00,   /* ? not written */
0393 //      0x3F, 0x03, /* 0E-0F */
0394         0x3C, 0x03,
0395         0x3C, 0x03, /* 10-11 */
0396         0x1A,   /* 12 */
0397         0x2A,   /* 13 */
0398         0x1C, 0x3D, 0x14, /* 14-16 */
0399         0x9C, 0x01, /* 17-18 */
0400         0x00,   /* 19 */
0401         0xFE,   /* 1A */
0402         0x7E,   /* 1B */
0403         0x60,   /* 1C */
0404         0x05,   /* 1D */
0405 //      0x89, 0x03, /* 1E-1F */
0406         0xAD, 0x03,
0407 //      0x72,   /* 20 */
0408         0xA5,
0409         0x07,   /* 21 */
0410 //      0x72,   /* 22 */
0411         0xA5,
0412         0x00,   /* 23 */
0413         0x00,   /* 24 */
0414         0x00,   /* 25 */
0415         0x08,   /* 26 */
0416         0x04,   /* 27 */
0417         0x00,   /* 28 */
0418         0x1A,   /* 29 */
0419         0x55, 0x01, /* 2A-2B */
0420         0x26,   /* 2C */
0421         0x07, 0x7E, /* 2D-2E */
0422         0x02, 0x54, /* 2F-30 */
0423         0xB0, 0x00, /* 31-32 */
0424         0x14,   /* 33 */
0425         0x49,   /* 34 */
0426         0x00,   /* 35 written multiple times */
0427         0x00,   /* 36 not written */
0428         0xA3,   /* 37 */
0429         0xC8,   /* 38 */
0430         0x22,   /* 39 */
0431         0x02,   /* 3A */
0432         0x22,   /* 3B */
0433         0x3F, 0x03, /* 3C-3D */
0434         0x00,   /* 3E written multiple times */
0435         0x00,   /* 3F not written */
0436     } };
0437     static const struct mavenregs ntscregs = { {
0438         0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
0439         0x00,
0440         0x00,   /* test */
0441         0xF9,   /* modified by code (F9 written...) */
0442         0x00,   /* ? not written */
0443         0x7E,   /* 08 */
0444         0x43,   /* 09 */
0445         0x7E,   /* 0A */
0446         0x3D,   /* 0B */
0447         0x00,   /* 0C */
0448         0x00,   /* ? not written */
0449         0x41, 0x00, /* 0E-0F */
0450         0x3C, 0x00, /* 10-11 */
0451         0x17,   /* 12 */
0452         0x21,   /* 13 */
0453         0x1B, 0x1B, 0x24, /* 14-16 */
0454         0x83, 0x01, /* 17-18 */
0455         0x00,   /* 19 */
0456         0x0F,   /* 1A */
0457         0x0F,   /* 1B */
0458         0x60,   /* 1C */
0459         0x05,   /* 1D */
0460         //0x89, 0x02, /* 1E-1F */
0461         0xC0, 0x02, /* 1E-1F */
0462         //0x5F, /* 20 */
0463         0x9C,   /* 20 */
0464         0x04,   /* 21 */
0465         //0x5F, /* 22 */
0466         0x9C,   /* 22 */
0467         0x01,   /* 23 */
0468         0x02,   /* 24 */
0469         0x00,   /* 25 */
0470         0x0A,   /* 26 */
0471         0x05,   /* 27 */
0472         0x00,   /* 28 */
0473         0x10,   /* 29 */
0474         0xFF, 0x03, /* 2A-2B */
0475         0x24,   /* 2C */
0476         0x0F, 0x78, /* 2D-2E */
0477         0x00, 0x00, /* 2F-30 */
0478         0xB2, 0x04, /* 31-32 */
0479         0x14,   /* 33 */
0480         0x02,   /* 34 */
0481         0x00,   /* 35 written multiple times */
0482         0x00,   /* 36 not written */
0483         0xA3,   /* 37 */
0484         0xC8,   /* 38 */
0485         0x15,   /* 39 */
0486         0x05,   /* 3A */
0487         0x3B,   /* 3B */
0488         0x3C, 0x00, /* 3C-3D */
0489         0x00,   /* 3E written multiple times */
0490         0x00,   /* never written */
0491     } };
0492 
0493     if (norm == MATROXFB_OUTPUT_MODE_PAL) {
0494         *data = palregs;
0495         *outd = &paloutd;
0496     } else {
0497         *data = ntscregs;
0498         *outd = &ntscoutd;
0499     }
0500     return;
0501 }
0502 
0503 #define LR(x) cve2_set_reg(minfo, (x), m->regs[(x)])
0504 static void cve2_init_TV(struct matrox_fb_info *minfo,
0505              const struct mavenregs *m)
0506 {
0507     int i;
0508 
0509     LR(0x80);
0510     LR(0x82); LR(0x83);
0511     LR(0x84); LR(0x85);
0512     
0513     cve2_set_reg(minfo, 0x3E, 0x01);
0514     
0515     for (i = 0; i < 0x3E; i++) {
0516         LR(i);
0517     }
0518     cve2_set_reg(minfo, 0x3E, 0x00);
0519 }
0520 
0521 static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
0522     struct matrox_fb_info *minfo = md;
0523 
0524     dprintk(KERN_DEBUG "Computing, mode=%u\n", minfo->outputs[1].mode);
0525 
0526     if (mt->crtc == MATROXFB_SRC_CRTC2 &&
0527         minfo->outputs[1].mode != MATROXFB_OUTPUT_MODE_MONITOR) {
0528         const struct output_desc* outd;
0529 
0530         cve2_init_TVdata(minfo->outputs[1].mode, &minfo->hw.maven, &outd);
0531         {
0532             int blacklevel, whitelevel;
0533             g450_compute_bwlevel(minfo, &blacklevel, &whitelevel);
0534             minfo->hw.maven.regs[0x0E] = blacklevel >> 2;
0535             minfo->hw.maven.regs[0x0F] = blacklevel & 3;
0536             minfo->hw.maven.regs[0x1E] = whitelevel >> 2;
0537             minfo->hw.maven.regs[0x1F] = whitelevel & 3;
0538 
0539             minfo->hw.maven.regs[0x20] =
0540             minfo->hw.maven.regs[0x22] = minfo->altout.tvo_params.saturation;
0541 
0542             minfo->hw.maven.regs[0x25] = minfo->altout.tvo_params.hue;
0543 
0544             if (minfo->altout.tvo_params.testout) {
0545                 minfo->hw.maven.regs[0x05] |= 0x02;
0546             }
0547         }
0548         computeRegs(minfo, &minfo->hw.maven, mt, outd);
0549     } else if (mt->mnp < 0) {
0550         /* We must program clocks before CRTC2, otherwise interlaced mode
0551            startup may fail */
0552         mt->mnp = matroxfb_g450_setclk(minfo, mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
0553         mt->pixclock = g450_mnp2f(minfo, mt->mnp);
0554     }
0555     dprintk(KERN_DEBUG "Pixclock = %u\n", mt->pixclock);
0556     return 0;
0557 }
0558 
0559 static int matroxfb_g450_program(void* md) {
0560     struct matrox_fb_info *minfo = md;
0561     
0562     if (minfo->outputs[1].mode != MATROXFB_OUTPUT_MODE_MONITOR) {
0563         cve2_init_TV(minfo, &minfo->hw.maven);
0564     }
0565     return 0;
0566 }
0567 
0568 static int matroxfb_g450_verify_mode(void* md, u_int32_t arg) {
0569     switch (arg) {
0570         case MATROXFB_OUTPUT_MODE_PAL:
0571         case MATROXFB_OUTPUT_MODE_NTSC:
0572         case MATROXFB_OUTPUT_MODE_MONITOR:
0573             return 0;
0574     }
0575     return -EINVAL;
0576 }
0577 
0578 static int g450_dvi_compute(void* md, struct my_timming* mt) {
0579     struct matrox_fb_info *minfo = md;
0580 
0581     if (mt->mnp < 0) {
0582         mt->mnp = matroxfb_g450_setclk(minfo, mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
0583         mt->pixclock = g450_mnp2f(minfo, mt->mnp);
0584     }
0585     return 0;
0586 }
0587 
0588 static struct matrox_altout matroxfb_g450_altout = {
0589     .name       = "Secondary output",
0590     .compute    = matroxfb_g450_compute,
0591     .program    = matroxfb_g450_program,
0592     .verifymode = matroxfb_g450_verify_mode,
0593     .getqueryctrl   = g450_query_ctrl,
0594     .getctrl    = g450_get_ctrl,
0595     .setctrl    = g450_set_ctrl,
0596 };
0597 
0598 static struct matrox_altout matroxfb_g450_dvi = {
0599     .name       = "DVI output",
0600     .compute    = g450_dvi_compute,
0601 };
0602 
0603 void matroxfb_g450_connect(struct matrox_fb_info *minfo)
0604 {
0605     if (minfo->devflags.g450dac) {
0606         down_write(&minfo->altout.lock);
0607         tvo_fill_defaults(minfo);
0608         minfo->outputs[1].src = minfo->outputs[1].default_src;
0609         minfo->outputs[1].data = minfo;
0610         minfo->outputs[1].output = &matroxfb_g450_altout;
0611         minfo->outputs[1].mode = MATROXFB_OUTPUT_MODE_MONITOR;
0612         minfo->outputs[2].src = minfo->outputs[2].default_src;
0613         minfo->outputs[2].data = minfo;
0614         minfo->outputs[2].output = &matroxfb_g450_dvi;
0615         minfo->outputs[2].mode = MATROXFB_OUTPUT_MODE_MONITOR;
0616         up_write(&minfo->altout.lock);
0617     }
0618 }
0619 
0620 void matroxfb_g450_shutdown(struct matrox_fb_info *minfo)
0621 {
0622     if (minfo->devflags.g450dac) {
0623         down_write(&minfo->altout.lock);
0624         minfo->outputs[1].src = MATROXFB_SRC_NONE;
0625         minfo->outputs[1].output = NULL;
0626         minfo->outputs[1].data = NULL;
0627         minfo->outputs[1].mode = MATROXFB_OUTPUT_MODE_MONITOR;
0628         minfo->outputs[2].src = MATROXFB_SRC_NONE;
0629         minfo->outputs[2].output = NULL;
0630         minfo->outputs[2].data = NULL;
0631         minfo->outputs[2].mode = MATROXFB_OUTPUT_MODE_MONITOR;
0632         up_write(&minfo->altout.lock);
0633     }
0634 }
0635 
0636 EXPORT_SYMBOL(matroxfb_g450_connect);
0637 EXPORT_SYMBOL(matroxfb_g450_shutdown);
0638 
0639 MODULE_AUTHOR("(c) 2000-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
0640 MODULE_DESCRIPTION("Matrox G450/G550 output driver");
0641 MODULE_LICENSE("GPL");