Logo Search packages:      
Sourcecode: i810switch version File versions  Download package

i810switch.c

#include <stdarg.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>

#define VERSION "0.6.5beta"
#define CMD_LSPCI "lspci"

static const char *Opt_lcd = NULL;
static const char *Opt_crt = NULL;

00017 struct i810_par {
      unsigned char *mmio;
      int mem;
      int flag;
};

#define i810_readb(mmio_base, where)                     \
        *((volatile char *) (mmio_base + where))

#define i810_readw(mmio_base, where)                     \
        *((volatile short *) (mmio_base + where))

#define i810_readl(mmio_base, where)                     \
        *((volatile int *) (mmio_base + where))

#define i810_writeb(mmio_base, where, val)                              \
      *((volatile char *) (mmio_base + where)) = (volatile char) val

#define i810_writew(mmio_base, where, val)                              \
      *((volatile short *) (mmio_base + where)) = (volatile short) val

#define i810_writel(mmio_base, where, val)                              \
      *((volatile int *) (mmio_base + where)) = (volatile int) val

#define I810_MEMOPEN          1
#define I810_MMIO       2

/* chip types */
#define I810                  1
#define I830                  2
#define I855                    3
#define I915                    4


/* PCI IDs */
#define I810STR               "8086:7121"
#define I810ESTR        "8086:7123"
#define I810_DC100STR_1       "8086:7125"
#define I810_DC100STR_2       "8086:1102"
#define I810_IGSTR            "8086:1112"
#define I810_CFCSTR           "8086:1132"
#define I830STR               "8086:3577"
#define I845STR               "8086:2562"
#define I855STR               "8086:3582"
//#define I865STR             "8086:2572"
#define I915STR               "8086:2592"
#define MEMSTR                "Memory at"
#define NONPRSTR        "32-bit, non-prefetchable"

/* I810 registers */
#define I810_HVSYNC           0x05000 

#define I810_DCLK_0D          0x06000
#define I810_DCLK_1D          0x06004
#define I810_DCLK_0DS         0x06010
#define I810_PWR_CLKC         0x06014

#define I810_HTOTAL           0x60000
#define I810_HBLANK           0x60004
#define I810_HSYNC            0x60008
#define I810_VTOTAL           0x6000c
#define I810_VBLANK           0x60010
#define I810_VSYNC            0x60014
#define I810_LCDTV_C          0x60018
#define I810_OVRACT           0x6001c
#define I810_BCLRPAT          0x60020

#define I810_PIXCONF          0x70008

/* I830 registers */
#define I830_HTOTAL_A         0x60000
#define I830_HBLANK_A         0x60004
#define I830_HSYNC_A          0x60008
#define I830_VTOTAL_A         0x6000c
#define I830_VBLANK_A         0x60010
#define I830_VSYNC_A          0x60014
#define I830_PIPEASRC         0x6001c
#define I830_BCLRPAT_A        0x60020

#define I830_HTOTAL_B         0x61000
#define I830_HBLANK_B         0x61004
#define I830_HSYNC_B          0x61008
#define I830_VTOTAL_B         0x6100c
#define I830_VBLANK_B         0x61010
#define I830_VSYNC_B          0x61014
#define I830_PIPEBSRC         0x6101c
#define I830_BCLRPAT_B        0x61020

#define I830_DPLL_A           0x06014
#define I830_DPLL_B           0x06018

#define I830_FPA0       0x06040
#define I830_FPA1       0x06044
#define I830_FPA2       0x06048
#define I830_FPA3       0x0604c

#define I830_ADPA       0x61100
#define I830_DVOA       0x61120
#define I830_DVOB       0x61140
#define I830_DVOC       0x61160
#define I830_LVDS       0x61180

#define I830_ADPA_SRCDIM      0x61104
#define I830_DVOA_SRCDIM      0x61124
#define I830_DVOB_SRCDIM      0x61144
#define I830_DVOC_SRCDIM      0x61164
#define I830_LVDS_SRCDIM      0x61184

#define I830_PIPEACONF        0x70008
#define I830_PIPEBCONF        0x71008

#define I830_DSPACTRL         0x70180
#define I830_DSPBCTRL         0x71180

#define I830_DSPABASE         0x70184
#define I830_DSPASTRIDE       0x70188
#define I830_DSPBBASE         0x71184
#define I830_DSPBSTRIDE       0x71188

#define I830_DCLK_0D          0x06000
#define I830_DCLK_1D          0x06004
#define I830_DCLK_0DS         0x06010

#define I830_SWF0       0x71410
#define I830_SWF1       0x71414
#define I830_SWF2       0x71418
#define I830_SWF3       0x7141c
#define I830_SWF4       0x71420
#define I830_SWF5       0x71424
#define I830_SWF6       0x71428

#define I830_LCDTV_C            0x06014
#define I855_LCDTV_C            0x61204

static void release_resource(struct i810_par *par)
{
      if (par->flag & I810_MEMOPEN)
            close(par->mem);
      if (par->flag & I810_MMIO)
            munmap(par->mmio, 512 * 1024);
}

void probe_card_I810(struct i810_par *par)
{
      printf("  DCLK 0D=%08lX 1D=%08lX 0DS=%08lX\n",
            i810_readl(par->mmio, I810_DCLK_0D), i810_readl(par->mmio, I810_DCLK_1D),
              i810_readl(par->mmio, I810_DCLK_0DS));
      printf("  PWR_CLKC=%08lX HVSYNC=%08lX\n",
            i810_readl(par->mmio, I810_PWR_CLKC),
              i810_readl(par->mmio, I810_HVSYNC));
      printf("  020cc=%08lX 020d8=%08lX 020dc=%08lX\n",
            i810_readl(par->mmio, 0x20cc), i810_readl(par->mmio, 0x20d8),
            i810_readl(par->mmio, 0x20dc));
      printf("  HTOTAL=%08lX HBLANK=%08lX HSYNC=%08lX\n",
            i810_readl(par->mmio, I810_HTOTAL),
            i810_readl(par->mmio, I810_HBLANK),
            i810_readl(par->mmio, I810_HSYNC));
      printf("  VTOTAL=%08lX VBLANK=%08lX VSYNC=%08lX\n",
            i810_readl(par->mmio, I810_VTOTAL),
            i810_readl(par->mmio, I810_VBLANK),
            i810_readl(par->mmio, I810_VSYNC));
      printf("  OVRACT=%08lX PIXCONF=%08lX 70080=%08lX\n",
            i810_readl(par->mmio, I810_OVRACT),
            i810_readl(par->mmio, I810_PIXCONF),
            i810_readl(par->mmio, 0x70080));
}

void probe_card_I830(struct i810_par *par)
{
      printf("  DCLK 0D=%08lX 1D=%08lX 0DS=%08lX DPLL A=%08lX B=%08lX\n",
            i810_readl(par->mmio, I830_DCLK_0D), i810_readl(par->mmio, I830_DCLK_1D),
            i810_readl(par->mmio, I830_DCLK_0DS),
            i810_readl(par->mmio, I830_DPLL_A), i810_readl(par->mmio, I830_DPLL_B));
      printf("  ADPA=%08lX  DVO A=%08lX B=%08lX C=%08lX  LVDS=%08lX\n",
            i810_readl(par->mmio, I830_ADPA), i810_readl(par->mmio, I830_DVOA),
            i810_readl(par->mmio, I830_DVOB), i810_readl(par->mmio, I830_DVOC),
            i810_readl(par->mmio, I830_LVDS));
      printf("  DIM =%08lX  DIM A=%08lX B=%08lX C=%08lX       %08lX\n",
            i810_readl(par->mmio, I830_ADPA_SRCDIM), i810_readl(par->mmio, I830_DVOA_SRCDIM),
            i810_readl(par->mmio, I830_DVOB_SRCDIM), i810_readl(par->mmio, I830_DVOC_SRCDIM),
            i810_readl(par->mmio, I830_LVDS_SRCDIM));
      printf("  FPA %08lX %08lX %08lX %08lX\n",
            i810_readl(par->mmio, I830_FPA0), i810_readl(par->mmio, I830_FPA1),
            i810_readl(par->mmio, I830_FPA2), i810_readl(par->mmio, I830_FPA3));
      printf("  020cc=%08lX 020d8=%08lX 020dc=%08lX\n",
            i810_readl(par->mmio, 0x20cc), i810_readl(par->mmio, 0x20d8),
            i810_readl(par->mmio, 0x20dc));
      printf("  71280=%08lX 71400=%08lX\n",
            i810_readl(par->mmio, 0x71280), i810_readl(par->mmio, 0x71400));
      printf("  Pipe A\n");
      printf("    HTOTAL=%08lX HBLANK=%08lX HSYNC=%08lX\n",
            i810_readl(par->mmio, I830_HTOTAL_A),
            i810_readl(par->mmio, I830_HBLANK_A),
            i810_readl(par->mmio, I830_HSYNC_A));
      printf("    VTOTAL=%08lX VBLANK=%08lX VSYNC=%08lX\n",
            i810_readl(par->mmio, I830_VTOTAL_A),
            i810_readl(par->mmio, I830_VBLANK_A),
            i810_readl(par->mmio, I830_VSYNC_A));
      printf("    SOURCE=%08lX CONFIG=%08lX 70030=%08lX 70080=%08lX\n",
            i810_readl(par->mmio, I830_PIPEASRC),
            i810_readl(par->mmio, I830_PIPEACONF),
            i810_readl(par->mmio, 0x70030),
            i810_readl(par->mmio, 0x70080));
      printf("  Pipe B\n");
      printf("    HTOTAL=%08lX HBLANK=%08lX HSYNC=%08lX\n",
            i810_readl(par->mmio, I830_HTOTAL_B),
            i810_readl(par->mmio, I830_HBLANK_B),
            i810_readl(par->mmio, I830_HSYNC_B));
      printf("    VTOTAL=%08lX VBLANK=%08lX VSYNC=%08lX\n",
            i810_readl(par->mmio, I830_VTOTAL_B),
            i810_readl(par->mmio, I830_VBLANK_B),
            i810_readl(par->mmio, I830_VSYNC_B));
      printf("    SOURCE=%08lX CONFIG=%08lX 71030=%08lX 71080=%08lX\n",
            i810_readl(par->mmio, I830_PIPEBSRC),
            i810_readl(par->mmio, I830_PIPEBCONF),
            i810_readl(par->mmio, 0x71030),
            i810_readl(par->mmio, 0x71080));
      printf("  Display plane A\n");
      printf("    CTRL=%08lX BASE=%08lX STRIDE=%08lX\n",
            i810_readl(par->mmio, I830_DSPACTRL),
            i810_readl(par->mmio, I830_DSPABASE),
            i810_readl(par->mmio, I830_DSPASTRIDE));
      printf("  Display plane B\n");
      printf("    CTRL=%08lX BASE=%08lX STRIDE=%08lX\n",
            i810_readl(par->mmio, I830_DSPBCTRL),
            i810_readl(par->mmio, I830_DSPBBASE),
            i810_readl(par->mmio, I830_DSPBSTRIDE));
}

char *i810_chip(char **buff_ptr, int *len_ptr, FILE *pci_f, int* chiptype)
{
      int i;
      char *p;

      while (getline(buff_ptr, len_ptr, pci_f) > 0) {
            i = (p = strstr(*buff_ptr, I810STR)) != NULL ||
                  (p = strstr(*buff_ptr, I810ESTR)) != NULL ||
                  (p = strstr(*buff_ptr, I810_DC100STR_1)) != NULL ||
                  (p = strstr(*buff_ptr, I810_DC100STR_2)) != NULL ||
                  (p = strstr(*buff_ptr, I810_IGSTR)) != NULL ||
                  (p = strstr(*buff_ptr, I810_CFCSTR)) != NULL;
            if (i)
            {
                  *chiptype = I810;
                  return p;
            }

            i = (p = strstr(*buff_ptr, I830STR)) != NULL ||
#if defined (I865STR)
                  (p = strstr(*buff_ptr, I865STR)) != NULL ||
#endif /*defined (I865STR)*/
                  (p = strstr(*buff_ptr, I845STR)) != NULL;
            if (i)
            {
                  *chiptype = I830;
                  return p;
            }

            i = (p = strstr(*buff_ptr, I855STR)) != NULL;
            if (i)
            {
                  *chiptype = I855;
                  return p;
            }

            i = (p = strstr(*buff_ptr, I915STR)) != NULL;
            if (i)
            {
                  *chiptype = I915;
                  return p;
            }
      }
      return NULL;
}

unsigned long i810_addr(char **buff_ptr, int *len_ptr, FILE *pci_f)
{
      char *p;

      while (getline(buff_ptr, len_ptr, pci_f) > 0)
            if (strstr(*buff_ptr, NONPRSTR) != NULL) {
                  p = strstr(*buff_ptr, MEMSTR);
                  if (p != NULL)
                        return strtoul(p+sizeof(MEMSTR), NULL, 16);
            }
      return 0;
}

int i810_usage ()
{
      fprintf(stderr, "usage: i810switch [crt on/off] [lcd on/off] [probe]\n");
      fprintf(stderr, "  crt: enables/disables the output to the CRT display\n");
      fprintf(stderr, "  lcd: enables/disables the output to the LCD\n");
      fprintf(stderr, "  probe: dumps the video chipset registers\n");
      fprintf(stderr, "  no options: displays the current output status\n");
      return 1;
}

int main (int argc, char *argv[])
{
      struct i810_par par;
      unsigned long addr;
      int i, crt = -1, lcd = -1, probe = 0, err = 0, count = 0, chiptype, len = 0;
      FILE *pci_f;
      char *buff = NULL;
      char lspcistr[] = CMD_LSPCI " -v -d xxxx:xxxx";
      char *chip;

      putenv("PATH=/sbin:/usr/sbin:/bin:/usr/bin");

      while (--argc > 0) {
            argv++;
            if (!strcmp(argv[0], "crt")) {
                  if (--argc > 0) {
                        argv++;
                        if (!strcmp(argv[0], "on"))
                              crt = 1;
                        else if (!strcmp(argv[0], "off"))
                              crt = 0;
                        else
                              exit(i810_usage());
                  } else {
                        exit(i810_usage());
                  }
            } else if (!strcmp(argv[0], "lcd")) {
                  argv++;
                  if (--argc > 0) {
                        if (!strcmp(argv[0], "on"))
                              lcd = 1;
                        else if (!strcmp(argv[0], "off"))
                              lcd = 0;
                        else
                              exit(i810_usage());
                  } else {
                        exit(i810_usage());
                  }
            } else if (!strcmp(argv[0], "probe")) {
                  probe = 1;
            } else {
                  exit(i810_usage());
            }
      }

      pci_f = popen(CMD_LSPCI " -n", "r");
      if (!pci_f) {
            fprintf(stderr, "Something is wrong with lspci.\n");
            exit(1);
      }
      chip = i810_chip(&buff, &len, pci_f, &chiptype);
      if (chip == NULL) {
            fprintf(stderr, "PCI id of i810 is not recognized.\n");
            exit(1);
      }
      pclose(pci_f);

      {
            char *p = strstr(lspcistr, "xxxx:xxxx");
            if (p == 0) {
                  fprintf(stderr, "CMD_LSPCI is wrong.\n");
                  exit(1);
            }
            memcpy(p, chip, 9);
      }

      pci_f = popen(lspcistr, "r");
      if (!pci_f) {
            fprintf(stderr, "Something is wrong with lspci.\n");
            exit(1);
      }
      addr = i810_addr(&buff, &len, pci_f);
      if (addr == 0) {
            fprintf(stderr, "Something is wrong with lspci.\n");
            exit(1);
      }
      pclose(pci_f);

      memset(&par, 0, sizeof(struct i810_par));
      par.mem = open("/dev/mem", (crt+lcd == -2) ? O_RDONLY : O_RDWR);
      if (par.mem == -1) {
            i = errno;
            perror("/dev/mem");
            if (i == EACCES && geteuid() != 0)
                  fprintf(stderr, "Must have access to `/dev/mem'.\n");
            release_resource(&par);
            exit(1);
      }
      par.flag |= I810_MEMOPEN;

      par.mmio = mmap(NULL, 512 * 1024, (crt+lcd == -2) ? PROT_READ : PROT_WRITE | PROT_READ,
                  MAP_SHARED, par.mem, addr);
      if (!par.mmio) {
            release_resource(&par);
            exit(1);
      }

      par.flag |= I810_MMIO;

      if (probe)
      {
            char *chipname = (chiptype == I810) ? "i810" : "i830";
            printf("i810switch %s probe\n", VERSION);
            printf("%s (%s) io=0x%8lX\n", chipname, lspcistr + 12, addr);
            if (chiptype == I810)
            {
                  probe_card_I810(&par);
            } else {
                  probe_card_I830(&par);
            }
            release_resource(&par);
            exit(0);
      }

      if (crt+lcd == -2) {
            if (chiptype == I810) {
                  printf("CRT: ");
                  if (i810_readl(par.mmio, I810_PWR_CLKC) & 1)
                        printf("on\n");
                  else
                        printf("off\n");

                  printf("LCD: ");
                  if (i810_readl(par.mmio, I810_LCDTV_C) & 0xc00)
                        printf("off\n");
                  else
                        printf("on\n");
            }
            else if (chiptype == I830 || chiptype == I915) {
                  printf("CRT: ");
                  if (i810_readl(par.mmio, I830_ADPA) & 0x80000000)
                        printf("on\n");
                  else
                        printf("off\n");
                  printf("LCD: ");
                  if (i810_readl(par.mmio, I830_LCDTV_C) & 0x40000000)
                        printf("on\n");
                  else
                        printf("off\n");
            }
            else if (chiptype == I855) {
                  printf("CRT: ");
                  if (i810_readl(par.mmio, I830_ADPA) & 0x80000000)
                        printf("on\n");
                  else
                        printf("off\n");
                  printf("LCD: ");
                  if (i810_readl(par.mmio, I855_LCDTV_C) & 1)
                        printf("on\n");
                  else
                        printf("off\n");
            }
      }

      if (crt != -1) {
            if (chiptype == I810) {
                  int pwr_clkc = i810_readl(par.mmio, I810_PWR_CLKC);
                  int hvsync = i810_readl(par.mmio, I810_HVSYNC);

                  if (crt == 0) {
                        printf("Disabling CRT display...\n");
                        pwr_clkc &= ~1;
                        hvsync = 0xa0000;
                  } else {
                        printf("Enabling CRT display...\n");
                        pwr_clkc |= 1;
                        hvsync = 0;
                  }
                  i810_writel(par.mmio, I810_PWR_CLKC, pwr_clkc);
                  i810_writel(par.mmio, I810_HVSYNC, hvsync);
            }
            else if (chiptype == I830 || chiptype == I855 || chiptype == I915)
            {
                  int i830_adpa = i810_readl(par.mmio, I830_ADPA);
                  int dspactrl = i810_readl(par.mmio, I830_DSPACTRL);
                  int dspbctrl = i810_readl(par.mmio, I830_DSPBCTRL);
                  int pipe = 0;

                  /* Find active display plane, and use the same pipe it's using */
                  if (dspactrl & (1<<31))
                        pipe = (dspactrl & (1<<24)) >> 24;
                  else if (dspbctrl & (1<<31))
                        pipe = (dspbctrl & (1<<24)) >> 24;
                  else
                        fprintf(stderr, "Warning: No active display plane detected.  Trying pipe A.\n");
                  if (crt == 0) {
                        printf("Disabling CRT display...\n");
                        i830_adpa = (i830_adpa & ~0x80000000 & ~(pipe<<30)) | 0xc00;
                  } else {
                        printf("Enabling CRT display...\n");
                        i830_adpa = (i830_adpa | 0x80000000 | (pipe<<30)) & ~0xc00;
                  }
                  i810_writel(par.mmio, I830_ADPA, i830_adpa);
            }
      }

      if (lcd != -1) {
            if (chiptype == I810) {
                  int lcdtv_c = i810_readl(par.mmio, I810_LCDTV_C);
                  if (lcd == 0) {
                        printf("Disabling LCD...\n");
                        lcdtv_c |= 0xc00;
                  } else {
                        printf("Enabling LCD...\n");
                        lcdtv_c &= ~(0xc00); 
                  }
                  i810_writel(par.mmio, I810_LCDTV_C, lcdtv_c);
            }
            else if (chiptype == I830 || chiptype == I915) {
                  int lcdtv_c;
                  if (lcd == 0) {
                        printf("Disabling LCD...\n");
                        lcdtv_c = i810_readl(par.mmio, I830_LCDTV_C);
                        lcdtv_c &= ~(0x40000000);
                        i810_writel(par.mmio, I830_LCDTV_C, lcdtv_c);
                  } else {
                        printf("Enabling LCD...\n");
                        lcdtv_c = i810_readl(par.mmio, I830_LCDTV_C);
                        lcdtv_c |= 0x40000000;
                        i810_writel(par.mmio, I830_LCDTV_C, lcdtv_c);
                  }
            }
            else if (chiptype == I855) {
                  int lcdtv_c;
                  if (lcd == 0) {
                        printf("Disabling LCD...\n");
                        lcdtv_c = i810_readl(par.mmio, I855_LCDTV_C);
                        lcdtv_c &= ~(1);
                        i810_writel(par.mmio, I855_LCDTV_C, lcdtv_c);
                  } else {
                        printf("Enabling LCD...\n");
                        lcdtv_c |= 1;
                        i810_writel(par.mmio, I855_LCDTV_C, lcdtv_c);
                  }
            }
            else fprintf(stderr, "No LCD support for this chipset.\n");
      }

      release_resource(&par);
      exit(0);
}

Generated by  Doxygen 1.6.0   Back to index