| 1 | /* libcqcam - shared Color Quickcam routines
 | 
|---|
| 2 |  * Copyright (C) 1996-1998 by Patrick Reynolds
 | 
|---|
| 3 |  * Email: <no.email@noemail.com>
 | 
|---|
| 4 |  *
 | 
|---|
| 5 |  * This library is free software; you can redistribute it and/or
 | 
|---|
| 6 |  * modify it under the terms of the GNU Library General Public
 | 
|---|
| 7 |  * License as published by the Free Software Foundation; either
 | 
|---|
| 8 |  * version 2 of the License, or (at your option) any later version.
 | 
|---|
| 9 |  *
 | 
|---|
| 10 |  * This library is distributed in the hope that it will be useful,
 | 
|---|
| 11 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 12 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
|---|
| 13 |  * Library General Public License for more details.
 | 
|---|
| 14 |  *
 | 
|---|
| 15 |  * You should have received a copy of the GNU Library General Public
 | 
|---|
| 16 |  * License along with this library; if not, write to the
 | 
|---|
| 17 |  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 | 
|---|
| 18 |  * Boston, MA 02110-1301, USA.
 | 
|---|
| 19 |  */
 | 
|---|
| 20 | 
 | 
|---|
| 21 | // I/O ports wrapper code
 | 
|---|
| 22 | // This file might need tweaking if you're trying to port my code to other
 | 
|---|
| 23 | // x86 Unix platforms.  Code is already available for Linux, FreeBSD, and    
 | 
|---|
| 24 | // QNX; see the Makefile.
 | 
|---|
| 25 | //
 | 
|---|
| 26 | // QNX code by: Anders Arpteg <aa11ac@hik.se>
 | 
|---|
| 27 | // FreeBSD code by: Patrick Reynolds <reynolds@cs.duke.edu> and Charles
 | 
|---|
| 28 | //                  Henrich <henrich@msu.edu>
 | 
|---|
| 29 | 
 | 
|---|
| 30 | 
 | 
|---|
| 31 | //#include "config.h"
 | 
|---|
| 32 | 
 | 
|---|
| 33 | #include <stdio.h>
 | 
|---|
| 34 | #include <errno.h>
 | 
|---|
| 35 | 
 | 
|---|
| 36 | #ifdef LOCKING
 | 
|---|
| 37 | #include <fcntl.h>
 | 
|---|
| 38 | #include <sys/stat.h>
 | 
|---|
| 39 | #endif /* LOCKING */
 | 
|---|
| 40 | 
 | 
|---|
| 41 | #ifdef __linux__
 | 
|---|
| 42 |   #if defined(arm) || defined(__hppa__) || defined(__sparc__) || defined(__ppc__) || defined(__powerpc__) || defined(__s390__) || defined(__s390x__) || defined(__mips__) || defined(__mc68000__)
 | 
|---|
| 43 |   #include <fcntl.h>
 | 
|---|
| 44 |   #else
 | 
|---|
| 45 |   #include <sys/io.h>
 | 
|---|
| 46 |   #endif /* arm */
 | 
|---|
| 47 | #elif defined(QNX)
 | 
|---|
| 48 | #include <conio.h>
 | 
|---|
| 49 | #elif defined(__FreeBSD__)
 | 
|---|
| 50 | #include <sys/types.h>
 | 
|---|
| 51 | #include <machine/cpufunc.h>
 | 
|---|
| 52 | #elif defined(BSDI)
 | 
|---|
| 53 | #include <machine/inline.h>
 | 
|---|
| 54 | #elif defined(OPENBSD)
 | 
|---|
| 55 | #include <machine/pio.h>
 | 
|---|
| 56 | #elif defined(LYNX)
 | 
|---|
| 57 | #include "lynx-io.h"
 | 
|---|
| 58 | #elif defined(SOLARIS)
 | 
|---|
| 59 | #include "solaris-io.h"
 | 
|---|
| 60 | #else
 | 
|---|
| 61 | #error Please define a platform in the Makefile
 | 
|---|
| 62 | #endif /* which OS */
 | 
|---|
| 63 | 
 | 
|---|
| 64 | #include "port.h"
 | 
|---|
| 65 | 
 | 
|---|
| 66 | port_t::port_t(int iport) {
 | 
|---|
| 67 |   port = -1;
 | 
|---|
| 68 | 
 | 
|---|
| 69 | #ifdef LOCKING
 | 
|---|
| 70 |   if (lock(iport) == -1) {
 | 
|---|
| 71 | #ifdef DEBUG
 | 
|---|
| 72 |     fprintf(stderr, "port 0x%x already locked\n", iport);
 | 
|---|
| 73 | #endif /* DEBUG */
 | 
|---|
| 74 |     return;
 | 
|---|
| 75 |   }
 | 
|---|
| 76 | #endif /* LOCKING */
 | 
|---|
| 77 | 
 | 
|---|
| 78 | #ifdef LINUX
 | 
|---|
| 79 | #if defined(arm) || defined(__hppa__) || defined(__sparc__) || defined(__ppc__) || defined(__powerpc__) || defined(__s390__) || defined(__s390x__) || defined(__mips__) || defined(__mc68000__)
 | 
|---|
| 80 |   if ((devport = open("/dev/port", O_RDWR)) < 0) {
 | 
|---|
| 81 |     perror("open /dev/port");
 | 
|---|
| 82 |     return;
 | 
|---|
| 83 |   }
 | 
|---|
| 84 | #else
 | 
|---|
| 85 |   if (ioperm(iport, 3, 1) == -1) {
 | 
|---|
| 86 |     perror("ioperm()");
 | 
|---|
| 87 |     return;
 | 
|---|
| 88 |   }
 | 
|---|
| 89 | #endif /* arm */
 | 
|---|
| 90 | #elif defined(FREEBSD)
 | 
|---|
| 91 |   if ((devio = fopen("/dev/io", "r+")) == NULL) {
 | 
|---|
| 92 |     perror("fopen /dev/io");
 | 
|---|
| 93 |     return;
 | 
|---|
| 94 |   }
 | 
|---|
| 95 | #elif defined(OPENBSD)
 | 
|---|
| 96 |   if (i386_iopl(1) == -1) {
 | 
|---|
| 97 |     perror("i386_iopl");
 | 
|---|
| 98 |     return;
 | 
|---|
| 99 |   }
 | 
|---|
| 100 | #elif defined(LYNX)
 | 
|---|
| 101 |   if (io_access() < 0) {
 | 
|---|
| 102 |     perror("io_access");
 | 
|---|
| 103 |     return;
 | 
|---|
| 104 |   }
 | 
|---|
| 105 | #elif defined(SOLARIS)
 | 
|---|
| 106 |   if (openiop()) {
 | 
|---|
| 107 |     perror("openiop");
 | 
|---|
| 108 |     return;
 | 
|---|
| 109 |   }
 | 
|---|
| 110 | #endif /* which OS */
 | 
|---|
| 111 | 
 | 
|---|
| 112 |   port = iport;
 | 
|---|
| 113 |   port1 = port + 1;
 | 
|---|
| 114 |   port2 = port + 2;
 | 
|---|
| 115 |   control_reg = read_control();
 | 
|---|
| 116 | }
 | 
|---|
| 117 | 
 | 
|---|
| 118 | port_t::~port_t(void) {
 | 
|---|
| 119 | #ifdef LOCKING
 | 
|---|
| 120 |   unlock(port);
 | 
|---|
| 121 | #endif /* LOCKING */
 | 
|---|
| 122 | #ifdef LINUX
 | 
|---|
| 123 | #if defined(arm) || defined(__hppa__) || defined(__sparc__) || defined(__ppc__) || defined(__powerpc__) || defined(__s390__) || defined(__s390x__) || defined(__mips__) || defined(__mc68000__)
 | 
|---|
| 124 |   if (devport >= 0)
 | 
|---|
| 125 |     close(devport);
 | 
|---|
| 126 | #else
 | 
|---|
| 127 |   if (port > 0 && geteuid() == 0)
 | 
|---|
| 128 |     if (ioperm(port, 3, 0) != 0)  // drop port permissions -- still must
 | 
|---|
| 129 |                                   // be root
 | 
|---|
| 130 |       perror("ioperm()");
 | 
|---|
| 131 | #endif /* arm */
 | 
|---|
| 132 | #elif defined(FREEBSD)
 | 
|---|
| 133 |   if (devio != NULL)
 | 
|---|
| 134 |     fclose(devio);
 | 
|---|
| 135 | #elif defined(SOLARIS)
 | 
|---|
| 136 |   close(iopfd);
 | 
|---|
| 137 | #endif /* which OS */
 | 
|---|
| 138 | }
 | 
|---|
| 139 | 
 | 
|---|
| 140 | #ifdef LOCKING
 | 
|---|
| 141 | int port_t::lock(int portnum) {
 | 
|---|
| 142 |   char lockfile[80];
 | 
|---|
| 143 |   sprintf(lockfile, "/tmp/LOCK.qcam.0x%x", portnum);
 | 
|---|
| 144 |   while ((lock_fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == -1) {
 | 
|---|
| 145 |     if (errno != EEXIST) {
 | 
|---|
| 146 |       perror(lockfile);
 | 
|---|
| 147 |       return -1;
 | 
|---|
| 148 |     }
 | 
|---|
| 149 |     struct stat stat_buf;
 | 
|---|
| 150 |     if (lstat(lockfile, &stat_buf) < 0) continue;
 | 
|---|
| 151 |     if (S_ISLNK(stat_buf.st_mode) || stat_buf.st_uid != 0) {
 | 
|---|
| 152 |       if (unlink(lockfile)) {
 | 
|---|
| 153 |         if (errno == ENOENT) continue;
 | 
|---|
| 154 |         if (errno != EISDIR || (rmdir(lockfile) && errno != ENOENT)) {
 | 
|---|
| 155 |             /* known problem: if lockfile exists and is a non-empty
 | 
|---|
| 156 |                directory, we give up instead of doing an rm-r of it */
 | 
|---|
| 157 |           perror(lockfile);
 | 
|---|
| 158 |           return -1;
 | 
|---|
| 159 |         }
 | 
|---|
| 160 |       }
 | 
|---|
| 161 |       continue;
 | 
|---|
| 162 |     }
 | 
|---|
| 163 |     lock_fd = open(lockfile, O_WRONLY, 0600);
 | 
|---|
| 164 |     if (lock_fd == -1) {
 | 
|---|
| 165 |       perror(lockfile);
 | 
|---|
| 166 |       return -1;
 | 
|---|
| 167 |     }
 | 
|---|
| 168 |     break;
 | 
|---|
| 169 |   }
 | 
|---|
| 170 | 
 | 
|---|
| 171 |   static struct flock lock_info;
 | 
|---|
| 172 |   lock_info.l_type = F_WRLCK;
 | 
|---|
| 173 | #ifdef LOCK_FAIL
 | 
|---|
| 174 |   if (fcntl(lock_fd, F_SETLK, &lock_info) != 0) {
 | 
|---|
| 175 | #else
 | 
|---|
| 176 |   if (fcntl(lock_fd, F_SETLKW, &lock_info) != 0) {
 | 
|---|
| 177 | #endif /* LOCK_FAIL */
 | 
|---|
| 178 |     if (errno != EAGAIN)
 | 
|---|
| 179 |       perror("fcntl");
 | 
|---|
| 180 |     return -1;
 | 
|---|
| 181 |   }
 | 
|---|
| 182 |   chown(lockfile, getuid(), getgid());
 | 
|---|
| 183 | #ifdef DEBUG
 | 
|---|
| 184 |   fprintf(stderr, "Locked port 0x%x\n", portnum);
 | 
|---|
| 185 | #endif /* DEBUG */
 | 
|---|
| 186 |   return 0;
 | 
|---|
| 187 | }
 | 
|---|
| 188 |     
 | 
|---|
| 189 | void port_t::unlock(int portnum) {
 | 
|---|
| 190 |   if (portnum == -1)
 | 
|---|
| 191 |     return;
 | 
|---|
| 192 |   close(lock_fd);    // this clears the lock
 | 
|---|
| 193 |   char lockfile[80];
 | 
|---|
| 194 |   sprintf(lockfile, "/tmp/LOCK.qcam.0x%x", portnum);
 | 
|---|
| 195 |   if (unlink(lockfile)) perror(lockfile);
 | 
|---|
| 196 | #ifdef DEBUG
 | 
|---|
| 197 |   fprintf(stderr, "Unlocked port 0x%x\n", portnum);
 | 
|---|
| 198 | #endif /* DEBUG */
 | 
|---|
| 199 | }
 | 
|---|
| 200 | #endif /* LOCKING */
 | 
|---|