diff options
Diffstat (limited to 'sys/qcam/qcam-os.c')
-rw-r--r-- | sys/qcam/qcam-os.c | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/sys/qcam/qcam-os.c b/sys/qcam/qcam-os.c new file mode 100644 index 00000000..f6383e01 --- /dev/null +++ b/sys/qcam/qcam-os.c @@ -0,0 +1,246 @@ +/* qcam-Linux.c -- Linux-specific routines for accessing QuickCam */ + +/* Version 0.1, January 2, 1996 */ +/* Version 0.5, August 24, 1996 */ + + +/****************************************************************** + +Copyright (C) 1996 by Scott Laird + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + + +#include <stdio.h> +#include <unistd.h> +#ifdef TESTING +#include <errno.h> +#endif +#include <sys/io.h> + +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "qcam.h" +#include "qcam-Linux.h" + +int __inline__ read_lpstatus(const struct qcam *q) { return inb(q->port+1); } +int read_lpcontrol(const struct qcam *q) { return inb(q->port+2); } +int read_lpdata(const struct qcam *q) { return inb(q->port); } +void write_lpdata(const struct qcam *q, int d) { outb(d,q->port); } +void write_lpcontrol(const struct qcam *q, int d) { outb(d,q->port+2); } + +int enable_ports(const struct qcam *q) +{ + if(q->port<0x278) return 1; /* Better safe than sorry */ + if(q->port>0x3bc) return 1; + return (ioperm(q->port, 3, 1)); +} + +int disable_ports(const struct qcam *q) +{ + return (ioperm(q->port, 3, 0)); +} + +/* Lock port. This is currently sub-optimal, and is begging to be + fixed. It should check for dead locks. Any takers? */ + +/* qc_lock_wait + * This function uses POSIX fcntl-style locking on a file created in the + * /tmp directory. Because it uses the Unix record locking facility, locks + * are relinquished automatically on process termination, so "dead locks" + * are not a problem. (FYI, the lock file will remain after process + * termination, but this is actually desired so that the next process need + * not re-creat(2)e it... just lock it.) + * The wait argument indicates whether or not this funciton should "block" + * waiting for the previous lock to be relinquished. This is ideal so that + * multiple processes (eg. qcam) taking "snapshots" can peacefully coexist. + * - Dave Plonka (plonka@carroll1.cc.edu) + */ +int qc_lock_wait(struct qcam *q, int wait) +{ +#if 1 + static struct flock sfl; + + if (-1 == q->fd) /* we've yet to open the lock file */ + { + static char lockfile[128]; + + sprintf(lockfile,"/var/run/LOCK.qcam.0x%x",q->port); + if (-1 == (q->fd = open(lockfile, O_WRONLY | O_CREAT, 0666))) + { + perror("open"); + return 1; + } + +#ifdef TESTING + fprintf(stderr, "%s - %d: %s open(2)ed\n", __FILE__, __LINE__, lockfile); +#endif + + /* initialize the l_type memver to lock the file exclusively */ + sfl.l_type = F_WRLCK; + } + +#ifdef TESTING + if (0 != fcntl(q->fd, F_SETLK, &sfl)) /* non-blocking set lock */ +#else + if (0 != fcntl(q->fd, wait? F_SETLKW : F_SETLK, &sfl)) +#endif + { +#ifdef TESTING + perror("fcntl"); + if (EAGAIN != errno || !wait) return 1; + + fprintf(stderr, "%s - %d: waiting for exclusive lock on fd %d...\n", __FILE__, __LINE__, q->fd); + + if (0 != fcntl(q->fd, F_SETLKW, &sfl)) /* "blocking" set lock */ +#endif + { + perror("fcntl"); + return 1; + } + } + +#ifdef TESTING + fprintf(stderr, "%s - %d: fd %d locked exclusively\n", __FILE__, __LINE__, q->fd); +#endif + +#else + char lockfile[128], tmp[128]; + struct stat statbuf; + + sprintf(lockfile,"/var/run/LOCK.qcam.0x%x",q->port); + sprintf(tmp,"%s-%d",lockfile,getpid()); + + if ((creat(tmp,0)==-1) || + (link(tmp,lockfile)==-1) || + (stat(tmp,&statbuf)==-1) || + (statbuf.st_nlink==1)) + { +#ifdef DEBUGQC + perror("QuickCam Locked"); + if(unlink(tmp)==-1) + perror("Error unlinking temp file."); +#else + unlink(tmp); +#endif + return 1; + } + + unlink(tmp); + if (chown(lockfile,getuid(),getgid())==-1) + perror("Chown problems"); +#endif + + return 0; +} + +int qc_lock(struct qcam *q) +{ +#if 1 + return qc_lock_wait(q, 1 /*wait*/); +#else + return qc_lock_wait(q, 0 /*don't wait*/); +#endif +} + +/* Unlock port */ + +int qc_unlock(struct qcam *q) +{ + static struct flock sfl; +#if 1 + if (-1 == q->fd) + { /* port was not locked */ + return 1; + } + + /* clear the exclusive lock */ + sfl.l_type = F_UNLCK; + if (0 != fcntl(q->fd, F_SETLK, &sfl)) + { + perror("fcntl"); + return 1; + } + +#ifdef TESTING + fprintf(stderr, "%s - %d: fd %d unlocked\n", __FILE__, __LINE__, q->fd); +#endif + +#else + char lockfile[128]; + + sprintf(lockfile,"/var/run/LOCK.qcam.0x%x",q->port); + unlink(lockfile); /* What would I do with an error? */ +#endif + + return 0; +} + + +/* Probe for camera. Returns 0 if found, 1 if not found, sets + q->port.*/ + +int qc_probe(struct qcam *q) +{ + int ioports[]={0x378, 0x278, 0x3bc,0}; + int i=0; + + /* Attempt to get permission to access IO ports. Must be root */ + + while(ioports[i]!=0) { + q->port=ioports[i++]; + + if (qc_open(q)) { + perror("Can't get I/O permission"); + exit(1); + } + + if(qc_detect(q)) { + fprintf(stderr,"QuickCam detected at 0x%x\n",q->port); + qc_close(q); + return(0); + } + else + qc_close(q); + } + + return 1; +} + + +/* THIS IS UGLY. I need a short delay loop -- somthing well under a +millisecond. Unfortunately, adding 2 usleep(1)'s to qc_command slowed +it down by a factor of over 1000 over the same loop with 2 +usleep(0)'s, and that's too slow -- qc_start was taking over a second +to run. This seems to help, but if anyone has a good +speed-independent pause routine, please tell me. -- Scott */ + +void qc_wait(int val) +{ + int i; + + while(val--) + for(i=0;i<50000;i++); +} |