Legacy I/O ports and text mode

Michael Steil <[email protected]> Mon, 25 Jul 2005 12:44:12 +0200
Newsgroups gmane.linux.ports.xbox.devel
Message-ID <[email protected]>
Hi!

Abstract: I can enable the legacy functions (and thus possibly a text  
mode) in Linux, but not in Cromwell, help wanted!

After three years, today I continued investigating how to enable the  
legacy I/O registers and how to set up a text mode on the Xbox. :-)

*** Background ***
The original VGA card in the IBM AT had several I/O ports at I/O  
addresses around 0x3BX/0x3CX/0x3DX, and memory at 0xA0000 to 0xC0000  
in the standard addressing space. With the advent of PCI cards, this  
has changed: By default, all PCI VGA cards are VGA incompatible: They  
use Memory-Mapped-I/O (MMIO) instead of Port-I/O and have their  
linear framebuffers somewhere in the 32 bit addressing space. In  
systems with more then one VGA card, all cards except for the first  
one remain in this mode, as only one can have Port-I/O and memory at  
0xA0000. So all cards default to the PCI mode, and legacy mode has to  
be turned on.

So if you try to use the legacy VGA ports on an Xbox, nothing  
happens, because they have not been turned on. A standard VGA BIOS,  
MS-DOS-like applications and many operating system bootloaders expect  
legacy Port-I/O and legacy memory space to be enabled, so that's a  
problem on the Xbox.

*** What I did ***
I tried to enable the legacy features and use the legacy I/O ports to  
change the current video mode. If the mode change works (i.e.  
something on the screen is happening), then the ports have been  
successfully enabled.

I booted from a SmartXX (build 3345) and Cromwell 2.40 into Xebian.  
Inside Xebian, I ran the following code:

#include <asm/io.h>

void crtout(unsigned char reg, unsigned char data) {
     outb(reg, 0x3d4);
     outb(data, 0x3d5);
}

int main() {
     iopl(3);

     outb(0x01, 0x03c3);
     outb(0x20, 0x0094);
     outb(0x08, 0x46e8);
     outb(0x02, 0x4ae8);
     outb(0x01, 0x0102);
     outb(0x03, 0x03c2);

     crtout(0x00, 0x5F);
     crtout(0x01, 0x4F);
     crtout(0x02, 0x50); //*
     crtout(0x03, 0x82); //*
     crtout(0x04, 0x54);
     crtout(0x05, 0x80);
     crtout(0x06, 0xBF); //*
     crtout(0x07, 0x1F);
     crtout(0x08, 0x0); //*
     crtout(0x09, 0x4F); //*
     crtout(0x0A, 0x0E); // 0x2D); //*
     crtout(0x0B, 0x0F); // 0x0E); //*
     crtout(0x0C, 0x00); //*
     crtout(0x0D, 0x00); //*
     crtout(0x0E, 0x03); // 0x00); //*
     crtout(0x0F, 0xBE); // 0x40); //*
     crtout(0x10, 0x9C);
     crtout(0x11, 0x8E); //*
     crtout(0x12, 0x8F); //*
     crtout(0x13, 0x28); //*
     crtout(0x14, 0x1F); //*
     crtout(0x15, 0x96); //*
     crtout(0x16, 0xB9); //*
     crtout(0x17, 0xA3);

return 0;
}

This code indeed did something to the graphics hardware, only using  
Port-I/O, so it must have worked. I found out that the single line of

     outb(0x01, 0x03c3);

seemed to be enough to enable the legacy I/O ports.

Then I included the same code into Cromwell, but nothing happened. I  
have no idea why - perhaps the Linux framebuffer driver "xboxfb" does  
some setup that is required? The driver does not seem to do any Port- 
I?o anyway, but it does access many MMIO ports. Perhaps someone can  
help?

*** More Info ***
Here is some more info about this issue.

**** Related Ports ****
0x94 bit5=1 "enable VGA"
0x3c3 bit0=1 "video subsystem enable"
0x46e8 bit3=1 "enable I/O & video buffer"
0x4ae8 =0x02 "VGA mode"
0x102 bit0=1 "VGA sleep, disconnect"
0x3c2 bit1=1 "enable CPU RAM access" and bit0=1 "CRTC register at  
0x3d4" -> =0x03

**** some more VGA init code ****
Perhaps someone can make some sense out of all this.

steve's code:
     outb(0, 0x94);
     outb(8, 0x46e8);
     outb(1, 0x102);
     outb(1, 0x3c3);
     outb(1, 0x3c2);
     outb(0x28, 0x94);

s3 code:
     outb(0x16, 0x64e8);
     outb(0x16, 0x3c3);
     outb(1, 0x102);
     outb(0x0e, 0x46e8);
     outb(0x0e, 0x3c3);
     outb(0, 0x4ae8);

trio64/amiga (NetBSD grf_cv.c)
     outb(0x10, 0x03c3);
     outb(0x01, 0x0102);
     outb(0x08, 0x03c3);
     outb(0x03, 0x03c2);
     crtout(0x38, 0x48);
     crtout(0x39, 0xA5);

http://cvsweb.xfree86.org/cvsweb/xc/programs/Xserver/hw/xfree86/int10/ 
helper_exec.c?rev=1.27 has this code to *disable* VGA:

/*
* Lock/Unlock legacy VGA. Some Bioses try to be very clever and make
* an attempt to detect a legacy ISA card. If they find one they might
* act very strange: for example they might configure the card as a
* monochrome card. This might cause some drivers to choke.
* To avoid this we attempt legacy VGA by writing to all know VGA
* disable registers before we call the BIOS initialization and
* restore the original values afterwards. In beween we hold our
* breath. To get to a (possibly exising) ISA card need to disable
* our current PCI card.
*/
/*
* This is just for booting: we just want to catch pure
* legacy vga therefore we don't worry about mmio etc.
* This stuff should really go into vgaHW.c. However then
* the driver would have to load the vga-module prior to
* doing int10.
*/
void
LockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga)
{
     xf86SetCurrentAccess(FALSE, xf86Screens[pInt->scrnIndex]);
     vga->save_msr    = inb(pInt->ioBase + 0x03CC);
     vga->save_vse    = inb(pInt->ioBase + 0x03C3);
#ifndef __ia64__
     vga->save_46e8   = inb(pInt->ioBase + 0x46E8);
#endif
     vga->save_pos102 = inb(pInt->ioBase + 0x0102);
     outb(pInt->ioBase + 0x03C2, ~(CARD8)0x03 & vga->save_msr);
     outb(pInt->ioBase + 0x03C3, ~(CARD8)0x01 & vga->save_vse);
#ifndef __ia64__
     outb(pInt->ioBase + 0x46E8, ~(CARD8)0x08 & vga->save_46e8);
#endif
     outb(pInt->ioBase + 0x0102, ~(CARD8)0x01 & vga->save_pos102);
     xf86SetCurrentAccess(TRUE, xf86Screens[pInt->scrnIndex]);
}

void
UnlockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga)
{
     xf86SetCurrentAccess(FALSE, xf86Screens[pInt->scrnIndex]);
     outb(pInt->ioBase + 0x0102, vga->save_pos102);
#ifndef __ia64__
     outb(pInt->ioBase + 0x46E8, vga->save_46e8);
#endif
     outb(pInt->ioBase + 0x03C3, vga->save_vse);
     outb(pInt->ioBase + 0x03C2, vga->save_msr);
     xf86SetCurrentAccess(TRUE, xf86Screens[pInt->scrnIndex]);
}

http://lorien.handhelds.org/ftp.arm.linux.org.uk/kernel/v2.1/ 
LATEST.gz also included some interesting (and similar) code:

#define vga_outb(v,p)    writeb((v), CYBER2000_MEM_BASE+0x800000+(p))
#define vga_inb(p)    readb(CYBER2000_MEM_BASE+0x0800000+(p))

#define WRITE_CRTC(r,v) do { vga_outb((r), 0x3d4); vga_outb((v),  
0x3d5); } while (0)
#define WRITE_ATTR(r,v) do { vga_inb(0x3da); vga_outb((r), 0x3c0);  
vga_inb(0x3c1); vga_outb((v), 0x3c0); } while (0)
#define WRITE_SEQ(r,v)  do { vga_outb((r), 0x3c4); vga_outb((v),  
0x3c5); } while (0)
#define WRITE_GRF(r,v)    do { vga_outb((r), 0x3ce); vga_outb((v),  
0x3cf); } while (0)

     vga_outb(0x18, 0x46e8);
     vga_outb(0x01, 0x102);
     vga_outb(0x08, 0x46e8);

     mdelay(1);

     vga_outb(0xef, 0x3c2);
[...]

   Michael


-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
from IBM. Find simple to follow Roadmaps, straightforward articles,
informative Webcasts and more! Get everything you need to get up to
speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click