linux/drivers/video/fbdev/matrox/matroxfb_g450.c
<<
>>
Prefs
   1/*
   2 *
   3 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
   4 *
   5 * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
   6 *
   7 * Portions Copyright (c) 2001 Matrox Graphics Inc.
   8 *
   9 * Version: 1.65 2002/08/14
  10 *
  11 * See matroxfb_base.c for contributors.
  12 *
  13 */
  14
  15#include "matroxfb_base.h"
  16#include "matroxfb_misc.h"
  17#include "matroxfb_DAC1064.h"
  18#include "g450_pll.h"
  19#include <linux/matroxfb.h>
  20#include <asm/div64.h>
  21
  22#include "matroxfb_g450.h"
  23
  24/* Definition of the various controls */
  25struct mctl {
  26        struct v4l2_queryctrl desc;
  27        size_t control;
  28};
  29
  30#define BLMIN   0xF3
  31#define WLMAX   0x3FF
  32
  33static const struct mctl g450_controls[] =
  34{       { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER, 
  35          "brightness",
  36          0, WLMAX-BLMIN, 1, 370-BLMIN, 
  37          0,
  38        }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
  39        { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER, 
  40          "contrast",
  41          0, 1023, 1, 127, 
  42          0,
  43        }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
  44        { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
  45          "saturation",
  46          0, 255, 1, 165, 
  47          0,
  48        }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
  49        { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
  50          "hue",
  51          0, 255, 1, 0, 
  52          0,
  53        }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
  54        { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN,
  55          "test output",
  56          0, 1, 1, 0, 
  57          0,
  58        }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
  59};
  60
  61#define G450CTRLS ARRAY_SIZE(g450_controls)
  62
  63/* Return: positive number: id found
  64           -EINVAL:         id not found, return failure
  65           -ENOENT:         id not found, create fake disabled control */
  66static int get_ctrl_id(__u32 v4l2_id) {
  67        int i;
  68
  69        for (i = 0; i < G450CTRLS; i++) {
  70                if (v4l2_id < g450_controls[i].desc.id) {
  71                        if (g450_controls[i].desc.id == 0x08000000) {
  72                                return -EINVAL;
  73                        }
  74                        return -ENOENT;
  75                }
  76                if (v4l2_id == g450_controls[i].desc.id) {
  77                        return i;
  78                }
  79        }
  80        return -EINVAL;
  81}
  82
  83static inline int *get_ctrl_ptr(struct matrox_fb_info *minfo, unsigned int idx)
  84{
  85        return (int*)((char*)minfo + g450_controls[idx].control);
  86}
  87
  88static void tvo_fill_defaults(struct matrox_fb_info *minfo)
  89{
  90        unsigned int i;
  91        
  92        for (i = 0; i < G450CTRLS; i++) {
  93                *get_ctrl_ptr(minfo, i) = g450_controls[i].desc.default_value;
  94        }
  95}
  96
  97static int cve2_get_reg(struct matrox_fb_info *minfo, int reg)
  98{
  99        unsigned long flags;
 100        int val;
 101        
 102        matroxfb_DAC_lock_irqsave(flags);
 103        matroxfb_DAC_out(minfo, 0x87, reg);
 104        val = matroxfb_DAC_in(minfo, 0x88);
 105        matroxfb_DAC_unlock_irqrestore(flags);
 106        return val;
 107}
 108
 109static void cve2_set_reg(struct matrox_fb_info *minfo, int reg, int val)
 110{
 111        unsigned long flags;
 112
 113        matroxfb_DAC_lock_irqsave(flags);
 114        matroxfb_DAC_out(minfo, 0x87, reg);
 115        matroxfb_DAC_out(minfo, 0x88, val);
 116        matroxfb_DAC_unlock_irqrestore(flags);
 117}
 118
 119static void cve2_set_reg10(struct matrox_fb_info *minfo, int reg, int val)
 120{
 121        unsigned long flags;
 122
 123        matroxfb_DAC_lock_irqsave(flags);
 124        matroxfb_DAC_out(minfo, 0x87, reg);
 125        matroxfb_DAC_out(minfo, 0x88, val >> 2);
 126        matroxfb_DAC_out(minfo, 0x87, reg + 1);
 127        matroxfb_DAC_out(minfo, 0x88, val & 3);
 128        matroxfb_DAC_unlock_irqrestore(flags);
 129}
 130
 131static void g450_compute_bwlevel(const struct matrox_fb_info *minfo, int *bl,
 132                                 int *wl)
 133{
 134        const int b = minfo->altout.tvo_params.brightness + BLMIN;
 135        const int c = minfo->altout.tvo_params.contrast;
 136
 137        *bl = max(b - c, BLMIN);
 138        *wl = min(b + c, WLMAX);
 139}
 140
 141static int g450_query_ctrl(void* md, struct v4l2_queryctrl *p) {
 142        int i;
 143        
 144        i = get_ctrl_id(p->id);
 145        if (i >= 0) {
 146                *p = g450_controls[i].desc;
 147                return 0;
 148        }
 149        if (i == -ENOENT) {
 150                static const struct v4l2_queryctrl disctrl = 
 151                        { .flags = V4L2_CTRL_FLAG_DISABLED };
 152                        
 153                i = p->id;
 154                *p = disctrl;
 155                p->id = i;
 156                sprintf(p->name, "Ctrl #%08X", i);
 157                return 0;
 158        }
 159        return -EINVAL;
 160}
 161
 162static int g450_set_ctrl(void* md, struct v4l2_control *p) {
 163        int i;
 164        struct matrox_fb_info *minfo = md;
 165        
 166        i = get_ctrl_id(p->id);
 167        if (i < 0) return -EINVAL;
 168
 169        /*
 170         * Check if changed.
 171         */
 172        if (p->value == *get_ctrl_ptr(minfo, i)) return 0;
 173
 174        /*
 175         * Check limits.
 176         */
 177        if (p->value > g450_controls[i].desc.maximum) return -EINVAL;
 178        if (p->value < g450_controls[i].desc.minimum) return -EINVAL;
 179
 180        /*
 181         * Store new value.
 182         */
 183        *get_ctrl_ptr(minfo, i) = p->value;
 184
 185        switch (p->id) {
 186                case V4L2_CID_BRIGHTNESS:
 187                case V4L2_CID_CONTRAST:
 188                        {
 189                                int blacklevel, whitelevel;
 190                                g450_compute_bwlevel(minfo, &blacklevel, &whitelevel);
 191                                cve2_set_reg10(minfo, 0x0e, blacklevel);
 192                                cve2_set_reg10(minfo, 0x1e, whitelevel);
 193                        }
 194                        break;
 195                case V4L2_CID_SATURATION:
 196                        cve2_set_reg(minfo, 0x20, p->value);
 197                        cve2_set_reg(minfo, 0x22, p->value);
 198                        break;
 199                case V4L2_CID_HUE:
 200                        cve2_set_reg(minfo, 0x25, p->value);
 201                        break;
 202                case MATROXFB_CID_TESTOUT:
 203                        {
 204                                unsigned char val = cve2_get_reg(minfo, 0x05);
 205                                if (p->value) val |=  0x02;
 206                                else          val &= ~0x02;
 207                                cve2_set_reg(minfo, 0x05, val);
 208                        }
 209                        break;
 210        }
 211        
 212
 213        return 0;
 214}
 215
 216static int g450_get_ctrl(void* md, struct v4l2_control *p) {
 217        int i;
 218        struct matrox_fb_info *minfo = md;
 219        
 220        i = get_ctrl_id(p->id);
 221        if (i < 0) return -EINVAL;
 222        p->value = *get_ctrl_ptr(minfo, i);
 223        return 0;
 224}
 225
 226struct output_desc {
 227        unsigned int    h_vis;
 228        unsigned int    h_f_porch;
 229        unsigned int    h_sync;
 230        unsigned int    h_b_porch;
 231        unsigned long long int  chromasc;
 232        unsigned int    burst;
 233        unsigned int    v_total;
 234};
 235
 236static void computeRegs(struct matrox_fb_info *minfo, struct mavenregs *r,
 237                        struct my_timming *mt, const struct output_desc *outd)
 238{
 239        u_int32_t chromasc;
 240        u_int32_t hlen;
 241        u_int32_t hsl;
 242        u_int32_t hbp;
 243        u_int32_t hfp;
 244        u_int32_t hvis;
 245        unsigned int pixclock;
 246        unsigned long long piic;
 247        int mnp;
 248        int over;
 249        
 250        r->regs[0x80] = 0x03;   /* | 0x40 for SCART */
 251
 252        hvis = ((mt->HDisplay << 1) + 3) & ~3;
 253        
 254        if (hvis >= 2048) {
 255                hvis = 2044;
 256        }
 257        
 258        piic = 1000000000ULL * hvis;
 259        do_div(piic, outd->h_vis);
 260
 261        dprintk(KERN_DEBUG "Want %u kHz pixclock\n", (unsigned int)piic);
 262        
 263        mnp = matroxfb_g450_setclk(minfo, piic, M_VIDEO_PLL);
 264        
 265        mt->mnp = mnp;
 266        mt->pixclock = g450_mnp2f(minfo, mnp);
 267
 268        dprintk(KERN_DEBUG "MNP=%08X\n", mnp);
 269
 270        pixclock = 1000000000U / mt->pixclock;
 271
 272        dprintk(KERN_DEBUG "Got %u ps pixclock\n", pixclock);
 273
 274        piic = outd->chromasc;
 275        do_div(piic, mt->pixclock);
 276        chromasc = piic;
 277        
 278        dprintk(KERN_DEBUG "Chroma is %08X\n", chromasc);
 279
 280        r->regs[0] = piic >> 24;
 281        r->regs[1] = piic >> 16;
 282        r->regs[2] = piic >>  8;
 283        r->regs[3] = piic >>  0;
 284        hbp = (((outd->h_b_porch + pixclock) / pixclock)) & ~1;
 285        hfp = (((outd->h_f_porch + pixclock) / pixclock)) & ~1;
 286        hsl = (((outd->h_sync + pixclock) / pixclock)) & ~1;
 287        hlen = hvis + hfp + hsl + hbp;
 288        over = hlen & 0x0F;
 289        
 290        dprintk(KERN_DEBUG "WL: vis=%u, hf=%u, hs=%u, hb=%u, total=%u\n", hvis, hfp, hsl, hbp, hlen);
 291
 292        if (over) {
 293                hfp -= over;
 294                hlen -= over;
 295                if (over <= 2) {
 296                } else if (over < 10) {
 297                        hfp += 4;
 298                        hlen += 4;
 299                } else {
 300                        hfp += 16;
 301                        hlen += 16;
 302                }
 303        }
 304
 305        /* maybe cve2 has requirement 800 < hlen < 1184 */
 306        r->regs[0x08] = hsl;
 307        r->regs[0x09] = (outd->burst + pixclock - 1) / pixclock;        /* burst length */
 308        r->regs[0x0A] = hbp;
 309        r->regs[0x2C] = hfp;
 310        r->regs[0x31] = hvis / 8;
 311        r->regs[0x32] = hvis & 7;
 312        
 313        dprintk(KERN_DEBUG "PG: vis=%04X, hf=%02X, hs=%02X, hb=%02X, total=%04X\n", hvis, hfp, hsl, hbp, hlen);
 314
 315        r->regs[0x84] = 1;      /* x sync point */
 316        r->regs[0x85] = 0;
 317        hvis = hvis >> 1;
 318        hlen = hlen >> 1;
 319        
 320        dprintk(KERN_DEBUG "hlen=%u hvis=%u\n", hlen, hvis);
 321
 322        mt->interlaced = 1;
 323
 324        mt->HDisplay = hvis & ~7;
 325        mt->HSyncStart = mt->HDisplay + 8;
 326        mt->HSyncEnd = (hlen & ~7) - 8;
 327        mt->HTotal = hlen;
 328
 329        {
 330                int upper;
 331                unsigned int vtotal;
 332                unsigned int vsyncend;
 333                unsigned int vdisplay;
 334                
 335                vtotal = mt->VTotal;
 336                vsyncend = mt->VSyncEnd;
 337                vdisplay = mt->VDisplay;
 338                if (vtotal < outd->v_total) {
 339                        unsigned int yovr = outd->v_total - vtotal;
 340                        
 341                        vsyncend += yovr >> 1;
 342                } else if (vtotal > outd->v_total) {
 343                        vdisplay = outd->v_total - 4;
 344                        vsyncend = outd->v_total;
 345                }
 346                upper = (outd->v_total - vsyncend) >> 1;        /* in field lines */
 347                r->regs[0x17] = outd->v_total / 4;
 348                r->regs[0x18] = outd->v_total & 3;
 349                r->regs[0x33] = upper - 1;      /* upper blanking */
 350                r->regs[0x82] = upper;          /* y sync point */
 351                r->regs[0x83] = upper >> 8;
 352                
 353                mt->VDisplay = vdisplay;
 354                mt->VSyncStart = outd->v_total - 2;
 355                mt->VSyncEnd = outd->v_total;
 356                mt->VTotal = outd->v_total;
 357        }
 358}
 359
 360static void cve2_init_TVdata(int norm, struct mavenregs* data, const struct output_desc** outd) {
 361        static const struct output_desc paloutd = {
 362                .h_vis     = 52148148,  // ps
 363                .h_f_porch =  1407407,  // ps
 364                .h_sync    =  4666667,  // ps
 365                .h_b_porch =  5777778,  // ps
 366                .chromasc  = 19042247534182ULL, // 4433618.750 Hz
 367                .burst     =  2518518,  // ps
 368                .v_total   =      625,
 369        };
 370        static const struct output_desc ntscoutd = {
 371                .h_vis     = 52888889,  // ps
 372                .h_f_porch =  1333333,  // ps
 373                .h_sync    =  4666667,  // ps
 374                .h_b_porch =  4666667,  // ps
 375                .chromasc  = 15374030659475ULL, // 3579545.454 Hz
 376                .burst     =  2418418,  // ps
 377                .v_total   =      525,  // lines
 378        };
 379
 380        static const struct mavenregs palregs = { {
 381                0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
 382                0x00,
 383                0x00,   /* test */
 384                0xF9,   /* modified by code (F9 written...) */
 385                0x00,   /* ? not written */
 386                0x7E,   /* 08 */
 387                0x44,   /* 09 */
 388                0x9C,   /* 0A */
 389                0x2E,   /* 0B */
 390                0x21,   /* 0C */
 391                0x00,   /* ? not written */
 392//              0x3F, 0x03, /* 0E-0F */
 393                0x3C, 0x03,
 394                0x3C, 0x03, /* 10-11 */
 395                0x1A,   /* 12 */
 396                0x2A,   /* 13 */
 397                0x1C, 0x3D, 0x14, /* 14-16 */
 398                0x9C, 0x01, /* 17-18 */
 399                0x00,   /* 19 */
 400                0xFE,   /* 1A */
 401                0x7E,   /* 1B */
 402                0x60,   /* 1C */
 403                0x05,   /* 1D */
 404//              0x89, 0x03, /* 1E-1F */
 405                0xAD, 0x03,
 406//              0x72,   /* 20 */
 407                0xA5,
 408                0x07,   /* 21 */
 409//              0x72,   /* 22 */
 410                0xA5,
 411                0x00,   /* 23 */
 412                0x00,   /* 24 */
 413                0x00,   /* 25 */
 414                0x08,   /* 26 */
 415                0x04,   /* 27 */
 416                0x00,   /* 28 */
 417                0x1A,   /* 29 */
 418                0x55, 0x01, /* 2A-2B */
 419                0x26,   /* 2C */
 420                0x07, 0x7E, /* 2D-2E */
 421                0x02, 0x54, /* 2F-30 */
 422                0xB0, 0x00, /* 31-32 */
 423                0x14,   /* 33 */
 424                0x49,   /* 34 */
 425                0x00,   /* 35 written multiple times */
 426                0x00,   /* 36 not written */
 427                0xA3,   /* 37 */
 428                0xC8,   /* 38 */
 429                0x22,   /* 39 */
 430                0x02,   /* 3A */
 431                0x22,   /* 3B */
 432                0x3F, 0x03, /* 3C-3D */
 433                0x00,   /* 3E written multiple times */
 434                0x00,   /* 3F not written */
 435        } };
 436        static const struct mavenregs ntscregs = { {
 437                0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
 438                0x00,
 439                0x00,   /* test */
 440                0xF9,   /* modified by code (F9 written...) */
 441                0x00,   /* ? not written */
 442                0x7E,   /* 08 */
 443                0x43,   /* 09 */
 444                0x7E,   /* 0A */
 445                0x3D,   /* 0B */
 446                0x00,   /* 0C */
 447                0x00,   /* ? not written */
 448                0x41, 0x00, /* 0E-0F */
 449                0x3C, 0x00, /* 10-11 */
 450                0x17,   /* 12 */
 451                0x21,   /* 13 */
 452                0x1B, 0x1B, 0x24, /* 14-16 */
 453                0x83, 0x01, /* 17-18 */
 454                0x00,   /* 19 */
 455                0x0F,   /* 1A */
 456                0x0F,   /* 1B */
 457                0x60,   /* 1C */
 458                0x05,   /* 1D */
 459                //0x89, 0x02, /* 1E-1F */
 460                0xC0, 0x02, /* 1E-1F */
 461                //0x5F, /* 20 */
 462                0x9C,   /* 20 */
 463                0x04,   /* 21 */
 464                //0x5F, /* 22 */
 465                0x9C,   /* 22 */
 466                0x01,   /* 23 */
 467                0x02,   /* 24 */
 468                0x00,   /* 25 */
 469                0x0A,   /* 26 */
 470                0x05,   /* 27 */
 471                0x00,   /* 28 */
 472                0x10,   /* 29 */
 473                0xFF, 0x03, /* 2A-2B */
 474                0x24,   /* 2C */
 475                0x0F, 0x78, /* 2D-2E */
 476                0x00, 0x00, /* 2F-30 */
 477                0xB2, 0x04, /* 31-32 */
 478                0x14,   /* 33 */
 479                0x02,   /* 34 */
 480                0x00,   /* 35 written multiple times */
 481                0x00,   /* 36 not written */
 482                0xA3,   /* 37 */
 483                0xC8,   /* 38 */
 484                0x15,   /* 39 */
 485                0x05,   /* 3A */
 486                0x3B,   /* 3B */
 487                0x3C, 0x00, /* 3C-3D */
 488                0x00,   /* 3E written multiple times */
 489                0x00,   /* never written */
 490        } };
 491
 492        if (norm == MATROXFB_OUTPUT_MODE_PAL) {
 493                *data = palregs;
 494                *outd = &paloutd;
 495        } else {
 496                *data = ntscregs;
 497                *outd = &ntscoutd;
 498        }
 499        return;
 500}
 501
 502#define LR(x) cve2_set_reg(minfo, (x), m->regs[(x)])
 503static void cve2_init_TV(struct matrox_fb_info *minfo,
 504                         const struct mavenregs *m)
 505{
 506        int i;
 507
 508        LR(0x80);
 509        LR(0x82); LR(0x83);
 510        LR(0x84); LR(0x85);
 511        
 512        cve2_set_reg(minfo, 0x3E, 0x01);
 513        
 514        for (i = 0; i < 0x3E; i++) {
 515                LR(i);
 516        }
 517        cve2_set_reg(minfo, 0x3E, 0x00);
 518}
 519
 520static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
 521        struct matrox_fb_info *minfo = md;
 522
 523        dprintk(KERN_DEBUG "Computing, mode=%u\n", minfo->outputs[1].mode);
 524
 525        if (mt->crtc == MATROXFB_SRC_CRTC2 &&
 526            minfo->outputs[1].mode != MATROXFB_OUTPUT_MODE_MONITOR) {
 527                const struct output_desc* outd;
 528
 529                cve2_init_TVdata(minfo->outputs[1].mode, &minfo->hw.maven, &outd);
 530                {
 531                        int blacklevel, whitelevel;
 532                        g450_compute_bwlevel(minfo, &blacklevel, &whitelevel);
 533                        minfo->hw.maven.regs[0x0E] = blacklevel >> 2;
 534                        minfo->hw.maven.regs[0x0F] = blacklevel & 3;
 535                        minfo->hw.maven.regs[0x1E] = whitelevel >> 2;
 536                        minfo->hw.maven.regs[0x1F] = whitelevel & 3;
 537
 538                        minfo->hw.maven.regs[0x20] =
 539                        minfo->hw.maven.regs[0x22] = minfo->altout.tvo_params.saturation;
 540
 541                        minfo->hw.maven.regs[0x25] = minfo->altout.tvo_params.hue;
 542
 543                        if (minfo->altout.tvo_params.testout) {
 544                                minfo->hw.maven.regs[0x05] |= 0x02;
 545                        }
 546                }
 547                computeRegs(minfo, &minfo->hw.maven, mt, outd);
 548        } else if (mt->mnp < 0) {
 549                /* We must program clocks before CRTC2, otherwise interlaced mode
 550                   startup may fail */
 551                mt->mnp = matroxfb_g450_setclk(minfo, mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
 552                mt->pixclock = g450_mnp2f(minfo, mt->mnp);
 553        }
 554        dprintk(KERN_DEBUG "Pixclock = %u\n", mt->pixclock);
 555        return 0;
 556}
 557
 558static int matroxfb_g450_program(void* md) {
 559        struct matrox_fb_info *minfo = md;
 560        
 561        if (minfo->outputs[1].mode != MATROXFB_OUTPUT_MODE_MONITOR) {
 562                cve2_init_TV(minfo, &minfo->hw.maven);
 563        }
 564        return 0;
 565}
 566
 567static int matroxfb_g450_verify_mode(void* md, u_int32_t arg) {
 568        switch (arg) {
 569                case MATROXFB_OUTPUT_MODE_PAL:
 570                case MATROXFB_OUTPUT_MODE_NTSC:
 571                case MATROXFB_OUTPUT_MODE_MONITOR:
 572                        return 0;
 573        }
 574        return -EINVAL;
 575}
 576
 577static int g450_dvi_compute(void* md, struct my_timming* mt) {
 578        struct matrox_fb_info *minfo = md;
 579
 580        if (mt->mnp < 0) {
 581                mt->mnp = matroxfb_g450_setclk(minfo, mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
 582                mt->pixclock = g450_mnp2f(minfo, mt->mnp);
 583        }
 584        return 0;
 585}
 586
 587static struct matrox_altout matroxfb_g450_altout = {
 588        .name           = "Secondary output",
 589        .compute        = matroxfb_g450_compute,
 590        .program        = matroxfb_g450_program,
 591        .verifymode     = matroxfb_g450_verify_mode,
 592        .getqueryctrl   = g450_query_ctrl,
 593        .getctrl        = g450_get_ctrl,
 594        .setctrl        = g450_set_ctrl,
 595};
 596
 597static struct matrox_altout matroxfb_g450_dvi = {
 598        .name           = "DVI output",
 599        .compute        = g450_dvi_compute,
 600};
 601
 602void matroxfb_g450_connect(struct matrox_fb_info *minfo)
 603{
 604        if (minfo->devflags.g450dac) {
 605                down_write(&minfo->altout.lock);
 606                tvo_fill_defaults(minfo);
 607                minfo->outputs[1].src = minfo->outputs[1].default_src;
 608                minfo->outputs[1].data = minfo;
 609                minfo->outputs[1].output = &matroxfb_g450_altout;
 610                minfo->outputs[1].mode = MATROXFB_OUTPUT_MODE_MONITOR;
 611                minfo->outputs[2].src = minfo->outputs[2].default_src;
 612                minfo->outputs[2].data = minfo;
 613                minfo->outputs[2].output = &matroxfb_g450_dvi;
 614                minfo->outputs[2].mode = MATROXFB_OUTPUT_MODE_MONITOR;
 615                up_write(&minfo->altout.lock);
 616        }
 617}
 618
 619void matroxfb_g450_shutdown(struct matrox_fb_info *minfo)
 620{
 621        if (minfo->devflags.g450dac) {
 622                down_write(&minfo->altout.lock);
 623                minfo->outputs[1].src = MATROXFB_SRC_NONE;
 624                minfo->outputs[1].output = NULL;
 625                minfo->outputs[1].data = NULL;
 626                minfo->outputs[1].mode = MATROXFB_OUTPUT_MODE_MONITOR;
 627                minfo->outputs[2].src = MATROXFB_SRC_NONE;
 628                minfo->outputs[2].output = NULL;
 629                minfo->outputs[2].data = NULL;
 630                minfo->outputs[2].mode = MATROXFB_OUTPUT_MODE_MONITOR;
 631                up_write(&minfo->altout.lock);
 632        }
 633}
 634
 635EXPORT_SYMBOL(matroxfb_g450_connect);
 636EXPORT_SYMBOL(matroxfb_g450_shutdown);
 637
 638MODULE_AUTHOR("(c) 2000-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 639MODULE_DESCRIPTION("Matrox G450/G550 output driver");
 640MODULE_LICENSE("GPL");
 641