Listing 1—Here is all the application-specific code I need for the Ethernet device. The rest of the system implements the TCP/IP stack.

#include <sys/wait.h>
#include <netinet/in.h>
#include <stdio.h>
#include <asm/io.h>
#define LPTDAT 0x278
#define LPTSTAT 0x279
#define LPTCTL 0x27a
#define MyPort 4321

main(){
  int s,ns;
  struct sockaddr_in sin;
  int slen;
  /* establish command port using TCP/IP */
  s = socket(AF_INET, SOCK_STREAM, 0); 
  sin.sin_addr.s_addr = htonl(0);
  sin.sin_port = htons(MyPort);
  bind(s,(struct sockaddr *)&sin,sizeof(sin));
  listen(s,1);
  while(1){
    slen = sizeof(sin);	/* wait for connection */
    ns = accept(s,(struct sockaddr *)&sin,&slen);
    if(ns < 0)
      continue;
    if(!fork()){	/* spawn off process to deal with connection */
      process(ns);
      exit(0);
    }
    close(ns);	/* close off socket in parent */
  }
}
#define CMDLEN 5
process(fd)
int fd;{
  char buf[128];
  int n,l;
  char req;
  int port, data;
  iopl(3);
  while ( 1 ){
    l = 0;
    while ( l < CMDLEN ){
      n = read(fd,&buf[l],(CMDLEN-l));
      if(n < 0) goto done_err;
      l += n;
    }
    buf[CMDLEN] = '\0';
    sscanf(buf,"%c%02x%02x",&req,&port,&data);
    switch(req){
      case 'q':
        goto done_normal;
      case 'w':
        le_write(port,data);
        break;
      case 'r':
        data = le_read(port);
        break;
      }
      sprintf(buf,"%02x",data);
      if(write(fd,buf,2)<0)
        goto done_err;
    }
  done_normal:
    close(fd);
    return(0);
  done_err:
    close(fd);
    return(-1);
}
le_read(p)
int p;{
  int x;
  outb(p,LPTDAT);	/* address */
  outb(0x01,LPTCTL);	/* address strobe */
  outb(0x00,LPTCTL);	/* reset address strobe */
  outb(0x02,LPTCTL);	/* read high nibble */
  x = inb(LPTSTAT)>>4;
  outb(0x0a,LPTCTL);	/* read strobe lower nibble */
  x |= (inb(LPTSTAT) & 0xf0);
  outb(0x00,LPTCTL);	/* reset read strobe */
  return(x);
}
le_write(p,x)
int p,x;{
  outb(p,LPTDAT);	/* address */
  outb(0x01,LPTCTL);	/* address strobe */
  outb(0x00,LPTCTL);	/* reset address strobe */
  outb(x,LPTDAT);	/* data */
  outb(0x04,LPTCTL);	/* write strobe */
  outb(0x00,LPTCTL);	/* reset write strobe */
}