#include <sys/types.h>
#include <sys/time.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/pcmcia.h>

void error(char *fmt, ...)
  {
  va_list args;
  va_start(args, fmt);
  fprintf(stderr, "dumbd: ");
  vfprintf(stderr, fmt, args);
  va_end(args);
  exit(EXIT_FAILURE);
  }
  
void syserror(char *fmt, ...)
  {
  va_list args;
  va_start(args, fmt);
  fprintf(stderr, "dumbd: ");
  vfprintf(stderr, fmt, args);
  perror("");
  va_end(args);
  exit(EXIT_FAILURE);
  }

void enable(int fd, char *name)
  {
  int val;
  struct pcmcia_io_map io[2] = {
    { 0, MAP_ACTIVE, 0x300, 0x30F },
    { 1, MAP_ACTIVE|MAP_CS16|MAP_16BIT, 0x310, 0x31F }
    };
  struct pcmcia_mem_map mem = {
    0, MAP_ACTIVE|MAP_ATTRIB, 0, 0xD6000L, 0xD6FFFL, 0x2000000L
    };

  val = PC_VCC_5V | PC_IOCARD;
  if (ioctl(fd, PCMCIA_SET_FLAGS, &val) < 0)
    syserror("ioctl(\"%s\", PCMCIA_SET_FLAGS)", name);
  if (ioctl(fd, PCMCIA_SET_IO_MAP, &io[0]) < 0)
    syserror("ioctl(\"%s\", PCMCIA_SET_IO_MAP)", name);
  if (ioctl(fd, PCMCIA_SET_IO_MAP, &io[1]) < 0)
    syserror("ioctl(\"%s\", PCMCIA_SET_IO_MAP)", name);
  if (ioctl(fd, PCMCIA_SET_MEM_MAP, &mem) < 0)
    syserror("ioctl(\"%s\", PCMCIA_SET_MEM_MAP)", name);
  val = 5;
  if (ioctl(fd, PCMCIA_SET_IRQ, &val) < 0)
    syserror("ioctl(\"%s\", PCMCIA_SET_IRQ)", name);
  if (system("./pc_eth0 start") != 0)
    syserror("system(\"pc_eth0 stop\")");
  }
  
void disable(int fd, char *name)
  {
  int val;
  val = PC_PWR_OFF;
  if (ioctl(fd, PCMCIA_SET_FLAGS, &val) < 0)
    syserror("ioctl(\"%s\", PCMCIA_SET_FLAGS)", name);
  if (system("./pc_eth0 stop") != 0)
    syserror("system(\"pc_eth0 stop\")");
  }
  
void main(int argc, char *argv[])
  {
  int fd[8], i, ret, val, event;
  fd_set fds;

  argv++; argc--;
  if (argc < 1) exit(-1);
  for (i = 0; i < argc; i++) {
    if ((fd[i] = open(argv[i], O_RDONLY)) < 0)
      syserror("open(\"%s\")", argv[i]);
    }

  for (i = 0; i < argc; i++) {
    if (ioctl(fd[i], PCMCIA_GET_STATUS, &val) < 0)
      syserror("ioctl(\"%s\", PCMCIA_GET_STATUS)", argv[i]);
    if (val & PC_DETECT) enable(fd[i], argv[i]);
    }

  for (;;) {
    FD_ZERO(&fds);
    for (i = 0; i < argc; i++) FD_SET(fd[i], &fds);
    if (select(10, &fds, NULL, NULL, NULL) < 0)
      syserror("select()");
    for (i = 0; i < argc; i++)
      if (FD_ISSET(fd[i], &fds)) {
        if ((ret = read(fd[i], &event, 4)) != 4)
          error("read(\"%s\") failed: ret = %d\n", argv[i], ret);
        if (ioctl(fd[i], PCMCIA_GET_STATUS, &val) < 0)
          syserror("ioctl(\"%s\", PCMCIA_GET_STATUS)", argv[i]);
        if (event & PC_DETECT) {
          if (val & PC_DETECT)
            enable(fd[i], argv[i]);
          else
            disable(fd[i], argv[i]);
          }
        }
    }
  }
