Writing to a parallel port

All about the OSDev Wiki. Discussions about the organization and general structure of articles and how to use the wiki. Request changes here if you don't know how to use the wiki.

Moderators: JAAman, klange, Octocontrabass, sortie, kmcguire, chase, thepowersgang, Owen, Combuster, AJ, 01000101, carbonBased, Candy, pcmattman

Post Reply
Smoppi
Posts: 3
Joined: Mon Oct 17, 2022 4:44 am
Freenode IRC: Sompi

Writing to a parallel port

Post by Smoppi »

Hello. I noticed that the parallel port writing routine in the OSDev wiki does not work. The problem is that after the byte is sent to the printer, the code does not wait for the printer to become receptive again - instead it immediately reads the control port, which causes things to happen too fast. It may work on a virtual machine, but not on a real hardware.

I wrote my own parallel port write routine that is loosely based on the original IBM PC's BIOS listings. My code does not read the control port at all after sending the byte because it is not needed - instead it just reads the status port until the printer becomes receptive to new commands again. This code works and it has already proved itself, I very often do printing with it.

Code: Select all

// a very short delay
void shortdelay(unsigned long interval);

unsigned short __far *parallelbase = (unsigned short __far*)0x00400008L;

// returns 0 if everything is ok
// returns 1 if there is no such parallel port
char parallel_init(unsigned short port, unsigned int mode)
{
  unsigned short control_port = parallelbase[port]+2;

  if(!parallelbase[port])
    return 1;

    // disable interrupts
    outbyte(control_port, inbyte(control_port) & ~0x10);   
 
    // reset the device and select the device and set direction to write   
    outbyte(control_port, inbyte(control_port) & ~(0x04 | 0x20));
    delay(50);
    outbyte(control_port, inbyte(control_port) | 0x04 | 0x08);

//    if mode is !0, switch auto line feed on (BIOS call does not do this!!)
    if(mode & 0x00FF)
      outbyte(control_port, inbyte(control_port) | 0x02);

    delay(1000);

  return 0;
}

// returns 0 if everything is OK
// returns 1 if a non-critical error happened (out of paper or something)
// returns 2 if a critical error happened
unsigned char parallel_write(unsigned short port, unsigned char chr)
{
  unsigned char retval;
  unsigned short control_port = parallelbase[port]+2;
  unsigned short printer_port = parallelbase[port];
  unsigned short status_port = parallelbase[port]+1;
  unsigned short retries = 0;


  if(inbyte(status_port) & 0x20)
    return 1;

  outbyte(printer_port, chr);

  // this check and delay is essential - otherwise things happen too fast!!!
  while(!(inbyte(status_port) & 0x80) && ++retries)
    shortdelay(LPT_PULSE_DELAY);

  retries = 0;

  shortdelay(LPT_PULSE_DELAY);

  outbyte(control_port, 0x0D);

  shortdelay(LPT_PULSE_DELAY);

  outbyte(control_port, 0x0C);

  inbyte(status_port);

  while(!(inbyte(status_port) & 0x80) && ++retries)
    shortdelay(LPT_PULSE_DELAY);

  if(!(inbyte(status_port) & 0x08))
    return 2;

  return 0;
 
}
Post Reply