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