These modes are grouped together because they use the same outbound data-transfer handshake. The term SPP (Standard Parallel Port) covers both compatibility and nibble modes.
Just negotiate or set the port to the desired transfer mode. Then you can read from or write to the port as to any other file.
#include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <linux/parport.h> #include <linux/ppdev.h> int bytes_read, bytes_written; unsigned char buf[120]; /* The size is arbitrary */ int parportfd = open(“/dev/parport0”, O_RDWR); int result = ioctl(parportfd,PPEXCL); int mode = IEEE1284_MODE_BYTE; /* or IEEE1284_MODE_NIBBLE, etc. */ int result = ioctl(parportfd,PPNEGOT,&mode); int bytes_read = read(parportfd,buf,120); /* to get bytes from the peripheral */ int bytes_written = write(parportfd,buf,sizeof(buf)); /*or send bytes to it */ |
The outbound handshake is the same for all of these modes when done in this way.
The basic sequence for writing a character in the slower modes is:
unsigned char data; /* The byte that you want to send to the peripheral */ unsigned char oldctl; unsigned char ctl; unsigned char status, i, maxtries = 100; unsigned char STROBE = 0x1; unsigned char DIRECTION = 0x20; unsigned char nBUSY = 0x80; int BASE = 0x378; /* or whatever */ int statusport = BASE + 1; int controlport = BASE + 2; oldctl = inb(controlport); /* get the current control port reading */ ctl = oldctl &= ˜DIRECTION; outb_p((ctl, controlport); /* Only if you leave a bidirectional port in the inward direction */ outb_p(data, BASE); /* write a byte to the data lines */ for (i = 0; i < maxtries; i++) { status = inb(statusport); /* if there is any possibility of the computer getting ahead of the peripheral, this should be tested repeatedly until it is clear */ if((status & nBUSY) == 0) break; } outb_p((ctl | STROBE), controlport); /* set the strobe flag */ outb_p((ctl &= ˜STROBE), controlport); /* and clear it again */ outb_p(oldctl, controlport); /* restore the port to its original condition */ |
Nibble mode allows inbound data transfers 4 bits at a time (hence the name “nibble”) through the status lines, rather than the data lines. This invention permitted parallel ports designed for output only to have a limited input capability.
unsigned char INIT = 0x4; unsigned char oldctl, ctl, data, low_nibble = 0, high_nibble = 0; oldctl = inb(controlport); ctl = oldctl | STROBE; outb(ctl, controlport); /* Ask for the low nibble */ low_nibble = (inb(statusport) & 0xF); ctl = ctl &= ˜STROBE; /* Ask for the high nibble */ high_nibble = (inb(statusport) & 0xF); data = ((low_nibble >> 4) + high_nibble) ^ 0x88; /* Adds the two nibbles together, 0x88 fixes the inverted lines */ for (i = 0; i < 2; i++) { ctl |= AUTOFEED; if (i == 0) ctl &= ˜INIT; buf[i] = inb(statusport); / *Get the data from the status lines. */ ctl = ˜AUTOFEED; /* Host tells peripheral that it has the data. */ ctl |= INIT; outb (ctl, controlport); /* Now turn the status line values into a coherent nibble */ buf[i] = (0xf & & (((buf[i] & ˜nACK) >> 3) | (˜buf[i] & nBUSY) >> 4)); } buf[0] = buf[0] | (buf[1] << 4); /* Put two nibbles together into a byte. */ |
The inbound transfer is similar to the outbound in Byte mode. In some circumstances you can get away with writing the function like SPP outbound mode, substituting AUTOFEED for STROBE. In other cases it's necessary to use the complete handshake as shown below.
unsigned char data; /* The byte that you want to read from the peripheral */ unsigned char oldctl; unsigned char ctl; unsigned char busy, i, maxtries = 100; /* number 100 here is arbitrary */ unsigned char STROBE = 0x1; unsigned char AUTOFEED = 0x2; unsigned char DIRECTION = 0x20; unsigned char nBUSY = 0x80; unsigned char nACK = 0x40; int BASE = 0x378; /* or whatever */ int statusport = BASE + 1; int controlport = BASE + 2; oldctl = inb(controlport); /* get the current control port reading */ ctl = oldctl | DIRECTION; outb((ctl, controlport); /* set the port to inbound transfer */ outb((ctl | AUTOFEED ), controlport); /* signals that the host is ready */ for(i=0;i = maxtries;i++){/* Check for a valid byte- can be skipped for speed */ status = inb(statusport); if(status & nACK != 0) break; } data = inb(BASE); /* grab the byte you want */ outb(ctl & ˜AUTOFEED); /* tells the peripheral that the byte has been received */ for(i=0; i = maxtries;i++) { /* if timing is OK, this can also be skipped */ status = inb(statusport); if(status & nACK == 0) break; /*nACK is cleared to acknowledge host response*/ } outb((ctl | STROBE), controlport); /*acknowledge nACK clear by pulsing STROBE */ outb((ctl & ˜STROBE),controlport); |