Blame src/ports.c

Packit d36e9b
/*
Packit d36e9b
 * libieee1284 - IEEE 1284 library
Packit d36e9b
 * Copyright (C) 2001, 2002, 2003  Tim Waugh <twaugh@redhat.com>
Packit d36e9b
 *
Packit d36e9b
 * This program is free software; you can redistribute it and/or modify
Packit d36e9b
 * it under the terms of the GNU General Public License as published by
Packit d36e9b
 * the Free Software Foundation; either version 2 of the License, or
Packit d36e9b
 * (at your option) any later version.
Packit d36e9b
 *
Packit d36e9b
 * This program is distributed in the hope that it will be useful,
Packit d36e9b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit d36e9b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit d36e9b
 * GNU General Public License for more details.
Packit d36e9b
 *
Packit d36e9b
 * You should have received a copy of the GNU General Public License
Packit d36e9b
 * along with this program; if not, write to the Free Software
Packit d36e9b
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Packit d36e9b
 */
Packit d36e9b
Packit d36e9b
#include <ctype.h>
Packit d36e9b
#include <fcntl.h>
Packit d36e9b
#include <stdio.h>
Packit d36e9b
#include <stdlib.h>
Packit d36e9b
#include <string.h>
Packit d36e9b
#include <sys/stat.h>
Packit d36e9b
#include <sys/types.h>
Packit d36e9b
#if defined __unix__ || defined __MINGW32__
Packit d36e9b
#include <dirent.h>
Packit d36e9b
#include <unistd.h>
Packit d36e9b
#endif
Packit d36e9b
Packit d36e9b
#include "config.h"
Packit d36e9b
#include "conf.h"
Packit d36e9b
#include "ieee1284.h"
Packit d36e9b
#include "debug.h"
Packit d36e9b
#include "detect.h"
Packit d36e9b
Packit d36e9b
#ifdef HAVE_CYGWIN_NT
Packit d36e9b
#ifdef __CYGWIN__
Packit d36e9b
#include <w32api/windows.h>
Packit d36e9b
#else /* Not cygwin really */
Packit d36e9b
/* Don't include windows.h if it isn't necessary. That's why this is here and
Packit d36e9b
*  not in the #if defined __MINGW32__ || defined _MSC_VER below. - dbjh */
Packit d36e9b
#include <windows.h>
Packit d36e9b
#endif /* __CYGWIN__ */
Packit d36e9b
#endif /* HAVE_CYGWIN_NT */
Packit d36e9b
Packit d36e9b
#if defined __MINGW32__ || defined _MSC_VER
Packit d36e9b
#define O_NOCTTY 0
Packit d36e9b
#endif
Packit d36e9b
Packit d36e9b
#define MAX_PORTS 20
Packit d36e9b
Packit d36e9b
static int
Packit d36e9b
compare_port (const void *a, const void *b)
Packit d36e9b
{
Packit d36e9b
  const struct parport * const*p1 = a, * const*p2 = b;
Packit d36e9b
  return strcmp ((*p1)->name, (*p2)->name);
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
static void
Packit d36e9b
sort_ports (struct parport_list *list)
Packit d36e9b
{
Packit d36e9b
  qsort (list->portv, list->portc, sizeof (struct parport *), compare_port);
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
static int
Packit d36e9b
add_port (struct parport_list *list, int flags,
Packit d36e9b
	  const char *name, const char *device, const char *udevice,
Packit d36e9b
	  unsigned long base, unsigned long hibase, int interrupt)
Packit d36e9b
{
Packit d36e9b
  struct parport *p;
Packit d36e9b
  struct parport_internal *priv;
Packit d36e9b
Packit d36e9b
  if (list->portc == (MAX_PORTS - 1))
Packit d36e9b
    /* Ridiculous. */
Packit d36e9b
    return E1284_NOMEM;
Packit d36e9b
Packit d36e9b
  p = malloc (sizeof *p);
Packit d36e9b
  if (!p)
Packit d36e9b
    return E1284_NOMEM;
Packit d36e9b
  memset (p, 0, sizeof *p);
Packit d36e9b
Packit d36e9b
  p->name = strdup (name);
Packit d36e9b
  if (!p->name)
Packit d36e9b
    {
Packit d36e9b
      free (p);
Packit d36e9b
      return E1284_NOMEM;
Packit d36e9b
    }
Packit d36e9b
Packit d36e9b
  p->filename = strdup(device);
Packit d36e9b
  if (!p->filename)
Packit d36e9b
    {
Packit d36e9b
      free ((char *) (p->name));
Packit d36e9b
      free (p);
Packit d36e9b
      return E1284_NOMEM;
Packit d36e9b
    }
Packit d36e9b
Packit d36e9b
  p->base_addr = base;
Packit d36e9b
  p->hibase_addr = hibase;
Packit d36e9b
Packit d36e9b
  priv = malloc (sizeof *priv);
Packit d36e9b
  if (!priv)
Packit d36e9b
    {
Packit d36e9b
      free ((char *) (p->name));
Packit d36e9b
      free ((char *) (p->filename));
Packit d36e9b
      free (p);
Packit d36e9b
      return E1284_NOMEM;
Packit d36e9b
    }
Packit d36e9b
  memset (priv, 0, sizeof *priv);
Packit d36e9b
Packit d36e9b
  priv->fn = malloc (sizeof *priv->fn);
Packit d36e9b
  if (!priv->fn)
Packit d36e9b
    {
Packit d36e9b
      free ((char *) (p->name));
Packit d36e9b
      free ((char *) (p->filename));
Packit d36e9b
      free (p);
Packit d36e9b
      free (priv);
Packit d36e9b
      return E1284_NOMEM;
Packit d36e9b
    }
Packit d36e9b
  memset (priv->fn, 0, sizeof *priv->fn);
Packit d36e9b
Packit d36e9b
  p->priv = priv;
Packit d36e9b
  priv->device = (char *) (p->filename);
Packit d36e9b
Packit d36e9b
  if (udevice)
Packit d36e9b
    {
Packit d36e9b
      priv->udevice = strdup (udevice);
Packit d36e9b
Packit d36e9b
      if (!priv->udevice)
Packit d36e9b
	{
Packit d36e9b
	  free ((char *) (p->name));
Packit d36e9b
	  free ((char *) (p->filename));
Packit d36e9b
	  free (p);
Packit d36e9b
	  free (priv->fn);
Packit d36e9b
	  free (priv);
Packit d36e9b
	  return E1284_NOMEM;
Packit d36e9b
	}
Packit d36e9b
    }
Packit d36e9b
Packit d36e9b
  priv->base = base;
Packit d36e9b
  priv->base_hi = 0;
Packit d36e9b
  if (interrupt < -1)
Packit d36e9b
    interrupt = -1;
Packit d36e9b
  priv->interrupt = interrupt;
Packit d36e9b
  priv->fd = -1;
Packit d36e9b
  priv->type = 0;
Packit d36e9b
  priv->opened = 0;
Packit d36e9b
  priv->claimed = 0;
Packit d36e9b
  priv->ref = 1;
Packit d36e9b
Packit d36e9b
  list->portv[list->portc++] = p;
Packit d36e9b
  sort_ports (list);
Packit d36e9b
  return 0;
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
static int
Packit d36e9b
populate_from_parport (struct parport_list *list, int flags)
Packit d36e9b
{
Packit d36e9b
#ifdef _MSC_VER
Packit d36e9b
  return E1284_SYS;
Packit d36e9b
#else
Packit d36e9b
  struct dirent *de;
Packit d36e9b
  DIR *parport = opendir ("/proc/parport");
Packit d36e9b
  if (!parport)
Packit d36e9b
    return E1284_SYS;
Packit d36e9b
Packit d36e9b
  de = readdir (parport);
Packit d36e9b
  while (de)
Packit d36e9b
    {
Packit d36e9b
      if (strcmp (de->d_name, ".") && strcmp (de->d_name, ".."))
Packit d36e9b
	{
Packit d36e9b
	  char device[50];
Packit d36e9b
	  char udevice[50];
Packit d36e9b
	  char hardware[50];
Packit d36e9b
	  unsigned long base = 0, hibase = 0;
Packit d36e9b
	  int interrupt = -1;
Packit d36e9b
	  int fd;
Packit d36e9b
Packit d36e9b
	  /* Device */
Packit d36e9b
	  if (capabilities & PPDEV_CAPABLE)
Packit d36e9b
	    {
Packit d36e9b
	      sprintf (device, "/dev/parport%s", de->d_name);
Packit d36e9b
	      sprintf (udevice, "/dev/parports/%s", de->d_name);
Packit d36e9b
	    }
Packit d36e9b
	  else
Packit d36e9b
	    {
Packit d36e9b
	      if (capabilities & IO_CAPABLE)
Packit d36e9b
		device[0] = '\0';
Packit d36e9b
	      else if (capabilities & DEV_PORT_CAPABLE)
Packit d36e9b
		strcpy (device, "/dev/port");
Packit d36e9b
	    }
Packit d36e9b
Packit d36e9b
	  /* Base and interrupt */
Packit d36e9b
	  sprintf (hardware, "/proc/parport/%s/hardware", de->d_name);
Packit d36e9b
	  fd = open (hardware, O_RDONLY | O_NOCTTY);
Packit d36e9b
	  if (fd >= 0)
Packit d36e9b
	    {
Packit d36e9b
	      char contents[500];
Packit d36e9b
	      ssize_t got = read (fd, contents, sizeof contents - 1);
Packit d36e9b
	      close (fd);
Packit d36e9b
	      if (got > 0)
Packit d36e9b
		{
Packit d36e9b
		  char *p;
Packit d36e9b
Packit d36e9b
		  contents[got - 1] = '\0';
Packit d36e9b
		  p = strstr (contents, "base:");
Packit d36e9b
		  if (p)
Packit d36e9b
		    {
Packit d36e9b
		      base = strtoul (p + strlen("base:"), NULL, 0);
Packit d36e9b
		      /* FIXME: read hibase too */
Packit d36e9b
		    }
Packit d36e9b
Packit d36e9b
		  p = strstr (contents, "irq:");
Packit d36e9b
		  if (p)
Packit d36e9b
		    {
Packit d36e9b
		      interrupt = strtol (p + strlen("irq:"), NULL, 0);
Packit d36e9b
		    }
Packit d36e9b
		}
Packit d36e9b
	    }
Packit d36e9b
Packit d36e9b
	  add_port (list, flags, de->d_name, device, udevice, base, hibase, interrupt);
Packit d36e9b
	}
Packit d36e9b
Packit d36e9b
      de = readdir (parport);
Packit d36e9b
    }
Packit d36e9b
Packit d36e9b
  closedir (parport);
Packit d36e9b
  return 0;
Packit d36e9b
#endif
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
static int
Packit d36e9b
populate_from_sys_dev_parport (struct parport_list *list, int flags)
Packit d36e9b
{
Packit d36e9b
#ifdef _MSC_VER
Packit d36e9b
  return E1284_SYS;
Packit d36e9b
#else
Packit d36e9b
  struct dirent *de;
Packit d36e9b
  DIR *parport = opendir ("/proc/sys/dev/parport");
Packit d36e9b
  if (!parport)
Packit d36e9b
    return E1284_SYS;
Packit d36e9b
Packit d36e9b
  de = readdir (parport);
Packit d36e9b
  while (de)
Packit d36e9b
    {
Packit d36e9b
      if (strcmp (de->d_name, ".") &&
Packit d36e9b
	  strcmp (de->d_name, "..") &&
Packit d36e9b
	  strcmp (de->d_name, "default"))
Packit d36e9b
	{
Packit d36e9b
	  char device[50];
Packit d36e9b
	  char udevice[50];
Packit d36e9b
	  unsigned long base = 0, hibase = 0;
Packit d36e9b
	  int interrupt = -1;
Packit d36e9b
	  size_t len = strlen (de->d_name) - 1;
Packit d36e9b
	  char filename[50];
Packit d36e9b
	  int fd;
Packit d36e9b
	  char *p;
Packit d36e9b
Packit d36e9b
	  while (len > 0 && isdigit (de->d_name[len]))
Packit d36e9b
	    len--;
Packit d36e9b
Packit d36e9b
	  p = de->d_name + len + 1;
Packit d36e9b
Packit d36e9b
	  /* Device */
Packit d36e9b
	  if (*p && capabilities & PPDEV_CAPABLE)
Packit d36e9b
	    {
Packit d36e9b
	      sprintf (device, "/dev/parport%s", p);
Packit d36e9b
	      sprintf (udevice, "/dev/parports/%s", p);
Packit d36e9b
	    }
Packit d36e9b
	  else
Packit d36e9b
	    {
Packit d36e9b
	      if (capabilities & IO_CAPABLE)
Packit d36e9b
		device[0] = '\0';
Packit d36e9b
	      else if (capabilities & DEV_PORT_CAPABLE)
Packit d36e9b
		strcpy (device, "/dev/port");
Packit d36e9b
	      else
Packit d36e9b
		device[0] = '\0';
Packit d36e9b
Packit d36e9b
	      udevice[0] = '\0';
Packit d36e9b
	    }
Packit d36e9b
Packit d36e9b
	  /* Base */
Packit d36e9b
	  sprintf (filename, "/proc/sys/dev/parport/%s/base-addr", de->d_name);
Packit d36e9b
	  fd = open (filename, O_RDONLY | O_NOCTTY);
Packit d36e9b
	  if (fd >= 0)
Packit d36e9b
	    {
Packit d36e9b
	      char contents[20];
Packit d36e9b
	      char *endptr;
Packit d36e9b
	      ssize_t got = read (fd, contents, sizeof contents - 1);
Packit d36e9b
	      close (fd);
Packit d36e9b
	      if (got > 0)
Packit d36e9b
	        {
Packit d36e9b
		  base = strtoul (contents, &endptr, 0);
Packit d36e9b
		  if (contents != endptr)
Packit d36e9b
		    hibase = strtoul (endptr, NULL, 0);
Packit d36e9b
		}
Packit d36e9b
	    }
Packit d36e9b
      
Packit d36e9b
	  /* Interrupt */
Packit d36e9b
	  sprintf (filename, "/proc/sys/dev/parport/%s/irq", de->d_name);
Packit d36e9b
	  fd = open (filename, O_RDONLY | O_NOCTTY);
Packit d36e9b
	  if (fd >= 0)
Packit d36e9b
	    {
Packit d36e9b
	      char contents[20];
Packit d36e9b
	      ssize_t got = read (fd, contents, sizeof contents - 1);
Packit d36e9b
	      close (fd);
Packit d36e9b
	      if (got > 0)
Packit d36e9b
		interrupt = strtol (contents, NULL, 0);
Packit d36e9b
	    }
Packit d36e9b
      
Packit d36e9b
	  add_port (list, flags, de->d_name, device, udevice, base, hibase, interrupt);
Packit d36e9b
	}
Packit d36e9b
Packit d36e9b
      de = readdir (parport);
Packit d36e9b
    }
Packit d36e9b
Packit d36e9b
  closedir (parport);
Packit d36e9b
  return 0;
Packit d36e9b
#endif
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
static int
Packit d36e9b
populate_nt_ports (struct parport_list *list, int flags)
Packit d36e9b
{
Packit d36e9b
#ifdef HAVE_CYGWIN_NT
Packit d36e9b
  char vdmname[] = "\\\\.\\$VDMLPT*";
Packit d36e9b
  HANDLE hf;
Packit d36e9b
  int i;
Packit d36e9b
  
Packit d36e9b
  for (i = 1; i <= 3; i++)
Packit d36e9b
  {
Packit d36e9b
    /* Name is \\.\$VDMLPT[1,2,3] */
Packit d36e9b
    vdmname[11] = i + '0';
Packit d36e9b
    hf = CreateFile(vdmname, GENERIC_READ | GENERIC_WRITE, 
Packit d36e9b
        0, NULL, OPEN_EXISTING, 0, NULL);
Packit d36e9b
    if (hf == INVALID_HANDLE_VALUE) continue;
Packit d36e9b
    CloseHandle(hf);
Packit d36e9b
    /* Friendly name is LPT1, LPT2, etc */
Packit d36e9b
    add_port (list, flags, vdmname+8, vdmname, NULL, 0, 0, -1);
Packit d36e9b
  }
Packit d36e9b
Packit d36e9b
#endif
Packit d36e9b
  return 0;
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
Packit d36e9b
static int
Packit d36e9b
populate_by_guessing (struct parport_list *list, int flags)
Packit d36e9b
{
Packit d36e9b
#if defined(HAVE_LINUX) || defined(HAVE_CYGWIN_9X) || defined(HAVE_OBSD_I386)
Packit d36e9b
  add_port (list, flags, "0x378", "/dev/port", NULL, 0x378, 0, -1);
Packit d36e9b
  add_port (list, flags, "0x278", "/dev/port", NULL, 0x278, 0, -1);
Packit d36e9b
  add_port (list, flags, "0x3bc", "/dev/port", NULL, 0x3bc, 0, -1);
Packit d36e9b
#elif defined(HAVE_FBSD_I386)
Packit d36e9b
  add_port (list, flags, "0x378", "/dev/io", NULL, 0x378, 0, -1);
Packit d36e9b
  add_port (list, flags, "0x278", "/dev/io", NULL, 0x278, 0, -1);
Packit d36e9b
  add_port (list, flags, "0x3bc", "/dev/io", NULL, 0x3bc, 0, -1);
Packit d36e9b
#elif defined(HAVE_SOLARIS)
Packit d36e9b
  add_port (list, flags, "0x378", "/devices/pseudo/iop@0:iop", NULL, 0x378, 0, -1);
Packit d36e9b
  add_port (list, flags, "0x278", "/devices/pseudo/iop@0:iop", NULL, 0x278, 0, -1);
Packit d36e9b
  add_port (list, flags, "0x3bc", "/devices/pseudo/iop@0:iop", NULL, 0x3bc, 0, -1);
Packit d36e9b
#endif
Packit d36e9b
  return 0;
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
/* Find out what ports there are. */
Packit d36e9b
int
Packit d36e9b
ieee1284_find_ports (struct parport_list *list, int flags)
Packit d36e9b
{
Packit d36e9b
  read_config_file ();
Packit d36e9b
Packit d36e9b
  list->portc = 0;
Packit d36e9b
  list->portv = malloc (sizeof(char*) * MAX_PORTS);
Packit d36e9b
  if (!list->portv)
Packit d36e9b
    return E1284_NOMEM;
Packit d36e9b
Packit d36e9b
  detect_environment (0);
Packit d36e9b
  if (capabilities & PROC_SYS_DEV_PARPORT_CAPABLE)
Packit d36e9b
    populate_from_sys_dev_parport (list, flags);
Packit d36e9b
  else if (capabilities & PROC_PARPORT_CAPABLE)
Packit d36e9b
    populate_from_parport (list, flags);
Packit d36e9b
  else if (capabilities & LPT_CAPABLE)
Packit d36e9b
    populate_nt_ports (list, flags);
Packit d36e9b
  else 
Packit d36e9b
    populate_by_guessing (list, flags);
Packit d36e9b
Packit d36e9b
  if (list->portc == 0)
Packit d36e9b
    {
Packit d36e9b
      free (list->portv);
Packit d36e9b
      list->portv = NULL;
Packit d36e9b
    }
Packit d36e9b
Packit d36e9b
  return 0;
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
/* Free up a parport_list structure. */
Packit d36e9b
void
Packit d36e9b
ieee1284_free_ports (struct parport_list *list)
Packit d36e9b
{
Packit d36e9b
  int i;
Packit d36e9b
Packit d36e9b
  for (i = 0; i < list->portc; i++)
Packit d36e9b
    deref_port (list->portv[i]);
Packit d36e9b
  
Packit d36e9b
  if (list->portv)
Packit d36e9b
    free (list->portv);
Packit d36e9b
Packit d36e9b
  list->portv = NULL;
Packit d36e9b
  list->portc = 0;
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
int
Packit d36e9b
deref_port (struct parport *p)
Packit d36e9b
{
Packit d36e9b
  struct parport_internal *priv = p->priv;
Packit d36e9b
  int count = --priv->ref;
Packit d36e9b
  if (!count)
Packit d36e9b
    {
Packit d36e9b
      debugprintf ("Destructor for port '%s'\n", p->name);
Packit d36e9b
      if (priv->fn)
Packit d36e9b
	free (priv->fn);
Packit d36e9b
      if (p->name)
Packit d36e9b
	free ((char *) (p->name));
Packit d36e9b
      if (priv->device)
Packit d36e9b
	free (priv->device);
Packit d36e9b
      if (priv->udevice)
Packit d36e9b
	free (priv->udevice);
Packit d36e9b
      free (priv);
Packit d36e9b
      free (p);
Packit d36e9b
    }
Packit d36e9b
  return count;
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
/*
Packit d36e9b
 * Local Variables:
Packit d36e9b
 * eval: (c-set-style "gnu")
Packit d36e9b
 * End:
Packit d36e9b
 */