/* * set_DSTN_size: Nathan Kurz * set the screen size to large or small for a Thinkpad 560 * with a 11.4 inch DSTN LCD with a Trident Cyber 9382 video chip. * The large screen size allows XFree86 to work in 800x600 mode. * It may work with other things, but no guarantees are made. * * Note: This program is only for a DSTN LCD. If you have a TFT display, * you should be using cy9382 instead! * * Much of this program is taken from other programs. In particular: * Cyber 9382 specifics from cy9382 Greg Minshall * with Linux hacks by Valery Petrov * Trident specifics: originally from Kendall Bennett * DSTN specifics from Xcyber * * To compile: * gcc -Wall -O -c set_DSTN_size.c -o set_DSTN_size.o * gcc -Wall -g -O -o set_DSTN_size set_DSTN_size.o * * To use: * set_DSTN_size large * startx * set_DSTN_size small * setfont * * I have had success with XF86_SVGA 3.1.2G and XF86_SVGA 3.2 * (I have had no success with XF86_SVGA 3.2A) * with the following XF86Config file: Section "Files" RgbPath "/usr/X11R6/lib/X11/rgb" FontPath "/usr/X11R6/lib/X11/fonts/misc/" #FontPath "/usr/X11R6/lib/X11/fonts/75dpi/:unscaled" #FontPath "/usr/X11R6/lib/X11/fonts/100dpi/:unscaled" FontPath "/usr/X11R6/lib/X11/fonts/Type1/" FontPath "/usr/X11R6/lib/X11/fonts/Speedo/" FontPath "/usr/X11R6/lib/X11/fonts/75dpi/" #FontPath "/usr/X11R6/lib/X11/fonts/100dpi/" EndSection Section "Keyboard" Protocol "Standard" AutoRepeat 500 5 EndSection Section "Pointer" Protocol "PS/2" Device "/dev/psaux" Emulate3Buttons Emulate3Timeout 50 EndSection Section "Monitor" Identifier "ThinkPad DSTN" VendorName "IBM" ModelName "ThinkPad 560" HorizSync 31.5-37.9 VertRefresh 55-65 Modeline "800x600" 40 800 840 968 1056 600 601 605 628 +hsync +vsync #ModeLine "800x600" 40 800 896 984 1000 600 608 610 633 # also works #ModeLine "800x600" 40 800 800 800 1054 600 600 600 633 # also works EndSection Section "Device" Identifier "ThinkPad Display" VendorName "Trident" BoardName "Trident 9382" #Chipset "cyber938x" # don't define this if using set_DSTN_size. EndSection Section "Screen" Driver "svga" Device "ThinkPad Display" Monitor "ThinkPad DSTN" DefaultColorDepth 8 Subsection "Display" Depth 8 Modes "800x600" ViewPort 0 0 Virtual 800 600 EndSubsection EndSection */ #include #include #include #include #include /* Note: On Linux, outb(value, port). I'm told BSD is outb(port, value) */ /* Note: This program could easily be made to work with BSD. See cy9382.c */ #define INB(x) inb(x) #define OUTB(x,y) outb(y,x) void set_register_index(short port, char index, char value) { switch (port) { case 0x3c5: case 0x3cf: OUTB(port-1, index); OUTB(port, value); break; case 0x3c1: INB(0x3da); /* set port to point at index */ OUTB(port-1, index); OUTB(port-1, value); break; default: fprintf(stderr, "unknown port 0x%x\n", port); exit(1); } } void set_register(short port, char value) { OUTB(port, value); } unsigned int get_register_index(short port, char index) { switch (port) { case 0x3c5: case 0x3cf: case 0x3d5: OUTB(port-1, index); return INB(port); break; case 0x3c1: INB(0x3da); /* set port to point at index */ OUTB(port, index); return INB(port); break; default: fprintf(stderr, "unknown port 0x%x\n", port); exit(1); /*NOTREACHED*/ } } unsigned int get_register(short port) { return (INB(port)); } inline static void tri_olddefs(void) { set_register(0x3c4, 0xb); set_register(0x3c5, 0xb); } inline static void tri_newdefs(void) { tri_olddefs(); (void) get_register(0x3c5); } inline static void tri_unlock(void) { unsigned a; tri_newdefs(); set_register(0x3c4, 0xe); a = get_register(0x3c5); a |= 0x80; /* unlock registers */ set_register(0x3c5, a); } inline static void tri_lock(void) { unsigned a; tri_newdefs(); set_register(0x3c4, 0xe); a = get_register(0x3c5); a &= ~0x80; /* lock registers */ set_register(0x3c5, a); } /* are we running on a cyber 9382? */ int is_cyber9382(void) { /* is it the right series (Trident 9660/80/9385/2)? */ if (get_register_index(0x3c5, 0xb) != 0xd3) { return 0; } /* is it a Cyber9382? */ /* note: this is the line to comment out if you are testing a Cyber9385 */ if (get_register_index(0x3c5, 0x9) != 0x33) { return 0; } return 1; /* Yes! */ } void die_usage(char *name) { fprintf(stderr, "usage: %s [large|small]\n", name); fprintf(stderr, "\n"); fprintf(stderr, "Changes the screen size for a DSTN Thinkpad 560\n"); fprintf(stderr, "with a Cyber9382 video chip.\n"); fprintf(stderr, "\n"); fprintf(stderr, "%s large\n", name); fprintf(stderr, " set screen to 800x600 for XF86_SVGA 3.2.\n"); fprintf(stderr, "%s small\n", name); fprintf(stderr, " set screen to 640x480 to restore when done.\n"); fprintf(stderr, "%s any_other_option\n", name); fprintf(stderr, " print this usage message.\n"); fprintf(stderr, "\n"); fprintf(stderr, "Note: This technique doesn't work with XF86 3.2A\n"); fprintf(stderr, "Note: Don't define 'Option cyber938x' in XF86Config.\n"); fprintf(stderr, "Note: Run 'setfont' after X is done to restore fonts.\n"); exit(1); } void main(int argc, char *argv[]) { char *command = NULL; char *action = NULL; int action_done = 0; command = argv[0]; if (argc >= 1) action = argv[1]; if (! action) die_usage(command); if (iopl(3)) { fprintf(stderr, "Can not enable port access through iopl(3)\n"); fprintf(stderr, "to get permission to issue instructions.)\n"); fprintf(stderr, "you may need to run %s as 'root'\n", command); fprintf(stderr, "(or, 'chown root %s; chmod 4755 %s'.)\n", command, command); die_usage(command); } if (! is_cyber9382() ) { fprintf(stderr, "%s Error: This isn't a Cyber9382\n", command); die_usage(command); } tri_unlock(); if (*action == 'l' || *action == 'L') { /* set to large screen */ set_register_index(0x3cf, 0x30, 0x00); printf("%s: Screen set to large.\n", command); action_done++; } if (*action == 's' || *action == 'S') { /* small screen */ set_register_index(0x3cf, 0x30, 0x81); printf("%s: Screen set to small.\n", command); action_done++; } tri_lock(); if (! action_done) die_usage(command); }