Page 1 of 1

Writing to a parallel port

Posted: Mon Oct 17, 2022 5:21 am
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;
  
}

Re: Writing to a parallel port

Posted: Mon Oct 17, 2022 10:42 pm
by Octocontrabass