summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/MAKEDEV54
-rw-r--r--etc/etc.i386/MAKEDEV54
-rw-r--r--share/man/man4/man4.i386/labpc.4151
-rw-r--r--sys/conf/NOTES5
-rw-r--r--sys/conf/files.i3863
-rw-r--r--sys/i386/conf/LINT5
-rw-r--r--sys/i386/conf/NOTES5
-rw-r--r--sys/i386/conf/files.i3863
-rw-r--r--sys/i386/i386/conf.c18
-rw-r--r--sys/i386/isa/labpc.c1051
10 files changed, 1341 insertions, 8 deletions
diff --git a/etc/MAKEDEV b/etc/MAKEDEV
index 10970eb..224d697 100644
--- a/etc/MAKEDEV
+++ b/etc/MAKEDEV
@@ -63,6 +63,11 @@
#
# Call units:
#
+# SCSI devices (other than CD-ROM, tape and disk)
+# uk* "unknown" device (supports ioctl calls only)
+# worm* WORM driver
+# pt* Processor Type (HP scanner, as one example)
+#
# Special purpose devices:
# bpf* packet filter
# speaker pc speaker
@@ -76,8 +81,9 @@
# tun Tunneling IP device
# spigot Video Spigot video aquisition card
# isdn* ISDN devices
+# labpc* National Instrument's Lab-PC and LAB-PC+
#
-# $Id: MAKEDEV,v 1.83 1995/04/23 12:02:21 ache Exp $
+# $Id: MAKEDEV,v 1.84 1995/04/26 08:07:30 bde Exp $
#
PATH=/sbin:/bin/:/usr/bin:/usr/sbin:
@@ -858,6 +864,52 @@ isdn*)
esac
;;
+# dufault@hda.com: If I do much more work on other A-D boards
+# then eventually we'll have a "ad" and "dio" interface and some of these
+# "labpcaio" ones will be gone.
+# labpcaio: D-A and A-D.
+# labpcdio: Digital in and Digital out.
+#
+labpc*)
+ umask 7
+ case $i in
+ labpcaio*)
+ name=labpcaio
+ unit=`expr $i : 'labpcaio\(.*\)'`
+ all="0 1 2 3 4 5 6 7"
+ offset=0
+ ;;
+ labpcdio*)
+ name=labpcdio
+ unit=`expr $i : 'labpcdio\(.*\)'`
+ all="0 1 2 3"
+ offset=128
+ ;;
+ *)
+ echo "Don't understand that labpc name"
+ exit
+ ;;
+ esac
+ if [ "X${unit}" = "X" ]; then
+ unit=all
+ fi
+ case $unit in
+ 0|1|2|3|4|5|6|7)
+ mknod $name$unit c 66 `expr $offset + $unit `
+ ;;
+ all)
+ for i in $all
+ do
+ mknod $name$i c 66 `expr $offset + $i `
+ done
+ ;;
+ *)
+ echo "No such LabPC unit: $unit"
+ ;;
+ esac
+ umask 77
+ ;;
+
local)
umask 0 # XXX should be elsewhere
sh MAKEDEV.local
diff --git a/etc/etc.i386/MAKEDEV b/etc/etc.i386/MAKEDEV
index 10970eb..224d697 100644
--- a/etc/etc.i386/MAKEDEV
+++ b/etc/etc.i386/MAKEDEV
@@ -63,6 +63,11 @@
#
# Call units:
#
+# SCSI devices (other than CD-ROM, tape and disk)
+# uk* "unknown" device (supports ioctl calls only)
+# worm* WORM driver
+# pt* Processor Type (HP scanner, as one example)
+#
# Special purpose devices:
# bpf* packet filter
# speaker pc speaker
@@ -76,8 +81,9 @@
# tun Tunneling IP device
# spigot Video Spigot video aquisition card
# isdn* ISDN devices
+# labpc* National Instrument's Lab-PC and LAB-PC+
#
-# $Id: MAKEDEV,v 1.83 1995/04/23 12:02:21 ache Exp $
+# $Id: MAKEDEV,v 1.84 1995/04/26 08:07:30 bde Exp $
#
PATH=/sbin:/bin/:/usr/bin:/usr/sbin:
@@ -858,6 +864,52 @@ isdn*)
esac
;;
+# dufault@hda.com: If I do much more work on other A-D boards
+# then eventually we'll have a "ad" and "dio" interface and some of these
+# "labpcaio" ones will be gone.
+# labpcaio: D-A and A-D.
+# labpcdio: Digital in and Digital out.
+#
+labpc*)
+ umask 7
+ case $i in
+ labpcaio*)
+ name=labpcaio
+ unit=`expr $i : 'labpcaio\(.*\)'`
+ all="0 1 2 3 4 5 6 7"
+ offset=0
+ ;;
+ labpcdio*)
+ name=labpcdio
+ unit=`expr $i : 'labpcdio\(.*\)'`
+ all="0 1 2 3"
+ offset=128
+ ;;
+ *)
+ echo "Don't understand that labpc name"
+ exit
+ ;;
+ esac
+ if [ "X${unit}" = "X" ]; then
+ unit=all
+ fi
+ case $unit in
+ 0|1|2|3|4|5|6|7)
+ mknod $name$unit c 66 `expr $offset + $unit `
+ ;;
+ all)
+ for i in $all
+ do
+ mknod $name$i c 66 `expr $offset + $i `
+ done
+ ;;
+ *)
+ echo "No such LabPC unit: $unit"
+ ;;
+ esac
+ umask 77
+ ;;
+
local)
umask 0 # XXX should be elsewhere
sh MAKEDEV.local
diff --git a/share/man/man4/man4.i386/labpc.4 b/share/man/man4/man4.i386/labpc.4
new file mode 100644
index 0000000..42e3eff
--- /dev/null
+++ b/share/man/man4/man4.i386/labpc.4
@@ -0,0 +1,151 @@
+.\"
+.\" Copyright (c) 1995 HD Associates, Inc.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Christopher G. Demetriou.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software withough specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"
+.rm ES
+.rm EE
+.de ES
+.Pp
+.nf
+.in +0.5i
+..
+.de EE
+.in -0.5i
+.fi
+..
+.Dd April 26, 1995
+.Dt LABPC 4 i386
+.Os FreeBSD
+.Sh NAME
+.Nm labpc
+.Nd
+National Instruments LABPC and LABPC+ driver
+.Sh SYNOPSIS
+.Cd "device labpc0 at isa? port 260 tty irq 5 vector labpcintr
+.Sh DESCRIPTION
+This supports the National Instruments LABPC and LABPC+ \fILow-Cost
+Multifunction I/O Board\fP.
+.sp
+This board provides 8 12 bit A-D input channels, 2 12 bit D-A output
+channels, and 3 8 bit digital I/O ports. It also supports setting
+up the National Instruments SCXI bus off the digital I/O ports,
+although that software is currently present in an external program
+and not as part of the driver.
+.Pp
+The selection of the input or output device, mode, and channel is
+through the minor number:
+.ES
+The 8 bit minor number format is UUSIDCCC, with
+ UU: Board unit.
+ S: SCAN bit for scan enable.
+ I: INTERVAL for interval support
+ D: 1: Digital I/O, 0: Analog I/O
+CCC: The channel selector:
+ ANALOG:
+ input: channel must be 0 to 7 for AD0 ... AD7
+ output: channel must be 0 to 2
+ 0: D-A 0
+ 1: D-A 1
+ 2: Alternate channel 0 then 1
+
+ DIGITAL:
+ input: Channel must be 0 to 2.
+ output: Channel must be 0 to 2.
+.EE
+.Pp
+The /dev/MAKEDEV script will make the basic analog and digital
+devices if you do "sh MAKEDEV labpcaio" and "sh MAKEDEV labpcdio",
+however, it won't make device entries for INTERVAL and SCAN devices.
+SCAN devices automatically scan over all channels from the channel
+number down to 0 (for example, a SCAN for /dev/ad7 will read channels
+AD7 ... AD0) while the INTERVAL device will wait for an external
+signal and then read all the channels from the selected channel
+number down to 0 as fast as it can. This is done by the hardware
+and not the driver (other than turning it on); See the \fILabPC+
+User's Manual\fP and the source code if this doesn't make sense to
+you.
+.Pp
+The driver supports several Analog I/O ioctl calls. These are defined
+in sys/aio.h and are intended to be compatable with other AIO board
+device drivers.
+.Pp
+AD_MICRO_PERIOD_SET takes a pointer to a long argument specifying
+the number of microseconds between samples.
+.Pp
+AD_MICRO_PERIOD_GET takes a pointer to a long argument and returns
+the current number of microseconds between samples.
+.Pp
+AD_NGAINS_GET takes a pointer to an integer and returns the number
+of different gain settings the board supports. This is 8 for the
+LabPC board.
+.Pp
+AD_NCHANS_GET takes a pointer to an integer and returns the number
+of channels the board supports. This is 8 for the LabPC board.
+.Pp
+AD_SUPPORTED_GAINS returns an array of NGAINS (the number obtained
+by AD_NGAINS_GET) doubles. These are the gains the board supports.
+.Pp
+AD_GAINS_SET takes an array of NCHANS (the number obtained by
+AD_NCHANS_GET) integers and sets the board gains. These are indices
+into the supported gain array, with one gain for each channel.
+.Pp
+AD_GAINS_GET takes an array of NCHANS (returned by AD_NCHANS_GET)
+integers and returns the cuurrent board gains.
+.Sh SEE ALSO
+.Xr aio 1
+.Sh BUGS
+In general, only those capabilities that I needed are present. In
+particular the following notable restrictions are present.
+.sp
+The analog input is only supported in a clocked conversion mode.
+.Pp
+You can only set the sample clock down to 15 Hz. Anything slower
+needs a modification to the driver to support TCINTEN in order to
+chain together the counters to get a lower clock rate.
+.Pp
+There is no support for clocked D-A output.
+.Pp
+The 8255 providing the digital I/O ports is supported only in mode
+0 (three 8 bit ports).
+.Pp
+There is support for the SCXI bus off the LABPC board. It is not
+in the driver but is a separate user process that accesses the
+digital I/O devices. Ask dufault@hda.com for it.
+.Pp
+MAKEDEV only makes the "basic" devices. You must make the INTERVAL
+or SCAN devices by hand.
+.Pp
+The INTERVAL device sets the clock rate as high as possible so that
+it samples all the channels as quickly as it can after the external
+signal. This is a silly restriction; it should simply use the
+clock setting.
+.Sh CAVEATS
+National Instrument's (like most other laboratory grade board
+vendors) definition of Low-Cost differs dramatically from many on
+the net.
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 671bdfd..c30911e 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
-# $Id: LINT,v 1.174 1995/04/24 05:33:59 phk Exp $
+# $Id: LINT,v 1.175 1995/04/25 03:44:04 phk Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@@ -638,6 +638,8 @@ device pca0 at isa? port IO_TIMER1 tty
# gp: National Instruments AT-GPIB and AT-GPIB/TNT board
# gsc: Genius GS-4500 hand scanner.
# joy: joystick
+# labpc: National Instrument's Lab-PC and Lab-PC+
+
#
# Notes on the spigot:
# The video spigot is at 0xad6. This port address can not be changed.
@@ -659,6 +661,7 @@ device gp0 at isa? port 0x2c0 tty
device gsc0 at isa? port "IO_GSC1" tty drq 3
device joy0 at isa? port "IO_GAME"
device cy0 at isa? tty irq 10 iomem 0xd4000 vector cyintr
+device labpc0 at isa? port 0x260 tty irq 5 vector labpcintr
#
# PCI devices:
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
index fefdea5..30adf58 100644
--- a/sys/conf/files.i386
+++ b/sys/conf/files.i386
@@ -1,7 +1,7 @@
# This file tells config what files go into building a kernel,
# files marked standard are always included.
#
-# $Id: files.i386,v 1.96 1995/04/23 09:12:00 julian Exp $
+# $Id: files.i386,v 1.97 1995/04/23 18:30:27 wollman Exp $
#
aic7xxx_asm optional ahc device-driver \
dependency "$S/dev/aic7xxx/aic7xxx_asm.c" \
@@ -89,6 +89,7 @@ i386/isa/if_zp.c optional zp device-driver
i386/isa/isa.c optional isa device-driver
i386/isa/joy.c optional joy device-driver
i386/isa/lpt.c optional lpt device-driver
+i386/isa/labpc.c optional labpc device-driver
i386/isa/mcd.c optional mcd device-driver
i386/isa/mse.c optional mse device-driver
i386/isa/ncr5380.c optional nca device-driver
diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT
index 671bdfd..c30911e 100644
--- a/sys/i386/conf/LINT
+++ b/sys/i386/conf/LINT
@@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
-# $Id: LINT,v 1.174 1995/04/24 05:33:59 phk Exp $
+# $Id: LINT,v 1.175 1995/04/25 03:44:04 phk Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@@ -638,6 +638,8 @@ device pca0 at isa? port IO_TIMER1 tty
# gp: National Instruments AT-GPIB and AT-GPIB/TNT board
# gsc: Genius GS-4500 hand scanner.
# joy: joystick
+# labpc: National Instrument's Lab-PC and Lab-PC+
+
#
# Notes on the spigot:
# The video spigot is at 0xad6. This port address can not be changed.
@@ -659,6 +661,7 @@ device gp0 at isa? port 0x2c0 tty
device gsc0 at isa? port "IO_GSC1" tty drq 3
device joy0 at isa? port "IO_GAME"
device cy0 at isa? tty irq 10 iomem 0xd4000 vector cyintr
+device labpc0 at isa? port 0x260 tty irq 5 vector labpcintr
#
# PCI devices:
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index 671bdfd..c30911e 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
-# $Id: LINT,v 1.174 1995/04/24 05:33:59 phk Exp $
+# $Id: LINT,v 1.175 1995/04/25 03:44:04 phk Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@@ -638,6 +638,8 @@ device pca0 at isa? port IO_TIMER1 tty
# gp: National Instruments AT-GPIB and AT-GPIB/TNT board
# gsc: Genius GS-4500 hand scanner.
# joy: joystick
+# labpc: National Instrument's Lab-PC and Lab-PC+
+
#
# Notes on the spigot:
# The video spigot is at 0xad6. This port address can not be changed.
@@ -659,6 +661,7 @@ device gp0 at isa? port 0x2c0 tty
device gsc0 at isa? port "IO_GSC1" tty drq 3
device joy0 at isa? port "IO_GAME"
device cy0 at isa? tty irq 10 iomem 0xd4000 vector cyintr
+device labpc0 at isa? port 0x260 tty irq 5 vector labpcintr
#
# PCI devices:
diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386
index fefdea5..30adf58 100644
--- a/sys/i386/conf/files.i386
+++ b/sys/i386/conf/files.i386
@@ -1,7 +1,7 @@
# This file tells config what files go into building a kernel,
# files marked standard are always included.
#
-# $Id: files.i386,v 1.96 1995/04/23 09:12:00 julian Exp $
+# $Id: files.i386,v 1.97 1995/04/23 18:30:27 wollman Exp $
#
aic7xxx_asm optional ahc device-driver \
dependency "$S/dev/aic7xxx/aic7xxx_asm.c" \
@@ -89,6 +89,7 @@ i386/isa/if_zp.c optional zp device-driver
i386/isa/isa.c optional isa device-driver
i386/isa/joy.c optional joy device-driver
i386/isa/lpt.c optional lpt device-driver
+i386/isa/labpc.c optional labpc device-driver
i386/isa/mcd.c optional mcd device-driver
i386/isa/mse.c optional mse device-driver
i386/isa/ncr5380.c optional nca device-driver
diff --git a/sys/i386/i386/conf.c b/sys/i386/i386/conf.c
index bf02cf5..60acb7d 100644
--- a/sys/i386/i386/conf.c
+++ b/sys/i386/i386/conf.c
@@ -42,7 +42,7 @@
* SUCH DAMAGE.
*
* from: @(#)conf.c 5.8 (Berkeley) 5/12/91
- * $Id: conf.c,v 1.82 1995/04/10 20:40:11 wollman Exp $
+ * $Id: conf.c,v 1.83 1995/04/14 15:13:26 dufault Exp $
*/
#include <sys/param.h>
@@ -1003,6 +1003,19 @@ d_ttycv_t rcdevtotty;
#define rcdevtotty nxdevtotty
#endif
+#include "labpc.h"
+#if NLABPC > 0
+d_open_t labpcopen;
+d_close_t labpcclose;
+d_strategy_t labpcstrategy;
+d_ioctl_t labpcioctl;
+#else
+#define labpcopen nxopen
+#define labpcclose nxclose
+#define labpcstrategy nxstrategy
+#define labpcioctl nxioctl
+#endif
+
/* open, close, read, write, ioctl, stop, reset, ttys, select, mmap, strat */
struct cdevsw cdevsw[] =
{
@@ -1214,6 +1227,9 @@ struct cdevsw cdevsw[] =
{ sctargopen, sctargclose, rawread, rawwrite, /*65*/
sctargioctl, nostop, nullreset, nodevtotty,/* sctarg */
seltrue, nommap, sctargstrategy },
+ { labpcopen, labpcclose, rawread, rawwrite, /*66*/
+ labpcioctl, nostop, nullreset, nodevtotty,/* labpc */
+ seltrue, nommap, labpcstrategy },
};
int nchrdev = sizeof (cdevsw) / sizeof (cdevsw[0]);
diff --git a/sys/i386/isa/labpc.c b/sys/i386/isa/labpc.c
new file mode 100644
index 0000000..e5ddeac
--- /dev/null
+++ b/sys/i386/isa/labpc.c
@@ -0,0 +1,1051 @@
+/*
+ * Copyright (c) 1995 HD Associates, Inc.
+ * All rights reserved.
+ *
+ * HD Associates, Inc.
+ * PO Box 276
+ * Pepperell, MA 01463-0276
+ * dufault@hda.com
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by HD Associates, Inc.
+ * 4. The name of HD Associates, Inc.
+ * may not be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Written by:
+ * Peter Dufault
+ * dufault@hda.com
+ */
+
+#include "labpc.h"
+#include "aio.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <sys/systm.h>
+#include <sys/devconf.h>
+
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/errno.h>
+#include <sys/buf.h>
+#include <machine/devconf.h>
+#include <machine/clock.h>
+
+
+#ifndef LABPC_DEFAULT_HERZ
+#define LABPC_DEFAULT_HERZ 500
+#endif
+
+/* Minor number:
+ * UUSIDCCC
+ * UU: Board unit.
+ * S: SCAN bit for scan enable.
+ * I: INTERVAL for interval support
+ * D: 1: Digital I/O, 0: Analog I/O
+ * CCC: Channel.
+ * Analog (D==0):
+ * input: channel must be 0 to 7.
+ * output: channel must be 0 to 2
+ * 0: D-A 0
+ * 1: D-A 1
+ * 2: Alternate channel 0 then 1
+ *
+ * Digital (D==1):
+ * input: Channel must be 0 to 2.
+ * output: Channel must be 0 to 2.
+ */
+
+/* Up to four boards:
+ */
+#define MAX_UNITS 4
+#define UNIT(dev) (((minor(dev) & 0xB0) >> 6) & 0x3)
+
+#define SCAN(dev) ((minor(dev) & 0x20) >> 5)
+#define INTERVAL(dev) ((minor(dev) & 0x10) >> 4)
+#define DIGITAL(dev) ((minor(dev) & 0x08) >> 3)
+
+/* Eight channels:
+ */
+
+#define CHAN(dev) (minor(dev) & 0x7)
+
+/* History: Derived from "dt2811.c" March 1995
+ */
+
+struct ctlr
+{
+ int err;
+#define DROPPED_INPUT 0x100
+ int base;
+ int unit;
+ unsigned long flags;
+#define BUSY 0x00000001
+
+ u_char cr_image[4];
+
+ u_short sample_us;
+
+ struct buf start_queue; /* Start queue */
+ struct buf *last; /* End of start queue */
+ u_char *data;
+ u_char *data_end;
+ long tmo; /* Timeout in Herz */
+
+ int gains[8];
+
+ dev_t dev; /* Copy of device */
+
+ void (*starter)(struct ctlr *ctlr, long count);
+ void (*stop)(struct ctlr *ctlr);
+ void (*intr)(struct ctlr *ctlr);
+
+ /* Digital I/O support. Copy of Data Control Register for 8255:
+ */
+ u_char dcr_val, dcr_is;
+
+ /* Device configuration structure:
+ */
+ struct kern_devconf kdc;
+};
+
+#ifdef LOUTB
+/* loutb is a slow outb for debugging. The overrun test may fail
+ * with this for some slower processors.
+ */
+static inline void loutb(int port, u_char val)
+{
+ outb(port, val);
+ DELAY(1);
+}
+#else
+#define loutb(port, val) outb(port, val)
+#endif
+
+struct ctlr **labpcs; /* XXX: Should be dynamic */
+
+/* CR_EXPR: A macro that sets the shadow register in addition to
+ * sending out the data.
+ */
+#define CR_EXPR(LABPC, CR, EXPR) do { \
+ (LABPC)->cr_image[CR - 1] EXPR ; \
+ loutb((LABPC)->base + (CR == 4 ? 0x0F : CR - 1), (LABPC)->cr_image[(CR - 1)]); \
+} while (0)
+
+#define CR_CLR(LABPC, CR) CR_EXPR(LABPC, CR, &=0)
+#define CR_REFRESH(LABPC, CR) CR_EXPR(LABPC, CR, &=0xff)
+#define CR_SET(LABPC, CR, EXPR) CR_EXPR(LABPC, CR, = EXPR)
+
+/* Configuration and Status Register Group.
+ */
+#define CR1(LABPC) ((LABPC)->base + 0x00) /* Page 4-5 */
+ #define SCANEN 0x80
+ #define GAINMASK 0x70
+ #define GAIN(LABPC, SEL) do { \
+ (LABPC)->cr_image[1 - 1] &= ~GAINMASK; \
+ (LABPC)->cr_image[1 - 1] |= (SEL << 4); \
+ loutb((LABPC)->base + (1 - 1), (LABPC)->cr_image[(1 - 1)]); \
+ } while (0)
+
+ #define TWOSCMP 0x08
+ #define MAMASK 0x07
+ #define MA(LABPC, SEL) do { \
+ (LABPC)->cr_image[1 - 1] &= ~MAMASK; \
+ (LABPC)->cr_image[1 - 1] |= SEL; \
+ loutb((LABPC)->base + (1 - 1), (LABPC)->cr_image[(1 - 1)]); \
+ } while (0)
+
+#define STATUS(LABPC) ((LABPC)->base + 0x00) /* Page 4-7 */
+ #define LABPCPLUS 0x80
+ #define EXTGATA0 0x40
+ #define GATA0 0x20
+ #define DMATC 0x10
+ #define CNTINT 0x08
+ #define OVERFLOW 0x04
+ #define OVERRUN 0x02
+ #define DAVAIL 0x01
+
+#define CR2(LABPC) ((LABPC)->base + 0x01) /* Page 4-9 */
+ #define LDAC1 0x80
+ #define LDAC0 0x40
+ #define _2SDAC1 0x20
+ #define _2SDAC0 0x10
+ #define TBSEL 0x08
+ #define SWTRIG 0x04
+ #define HWTRIG 0x02
+ #define PRETRIG 0x01
+ #define SWTRIGGERRED(LABPC) ((LABPC->cr_image[1]) & SWTRIG)
+
+#define CR3(LABPC) ((LABPC)->base + 0x02) /* Page 4-11 */
+ #define FIFOINTEN 0x20
+ #define ERRINTEN 0x10
+ #define CNTINTEN 0x08
+ #define TCINTEN 0x04
+ #define DIOINTEN 0x02
+ #define DMAEN 0x01
+
+ #define ALLINTEN 0x3E
+ #define FIFOINTENABLED(LABPC) ((LABPC->cr_image[2]) & FIFOINTEN)
+
+#define CR4(LABPC) ((LABPC)->base + 0x0F) /* Page 4-13 */
+ #define ECLKRCV 0x10
+ #define SE_D 0x08
+ #define ECKDRV 0x04
+ #define EOIRCV 0x02
+ #define INTSCAN 0x01
+
+/* Analog Input Register Group
+ */
+#define ADFIFO(LABPC) ((LABPC)->base + 0x0A) /* Page 4-16 */
+#define ADCLEAR(LABPC) ((LABPC)->base + 0x08) /* Page 4-18 */
+#define ADSTART(LABPC) ((LABPC)->base + 0x03) /* Page 4-19 */
+#define DMATCICLR(LABPC) ((LABPC)->base + 0x0A) /* Page 4-20 */
+
+/* Analog Output Register Group
+ */
+#define DAC0L(LABPC) ((LABPC)->base + 0x04) /* Page 4-22 */
+#define DAC0H(LABPC) ((LABPC)->base + 0x05) /* Page 4-22 */
+#define DAC1L(LABPC) ((LABPC)->base + 0x06) /* Page 4-22 */
+#define DAC1H(LABPC) ((LABPC)->base + 0x07) /* Page 4-22 */
+
+/* 8253 registers:
+ */
+#define A0DATA(LABPC) ((LABPC)->base + 0x14)
+#define A1DATA(LABPC) ((LABPC)->base + 0x15)
+#define A2DATA(LABPC) ((LABPC)->base + 0x16)
+#define AMODE(LABPC) ((LABPC)->base + 0x17)
+
+#define TICR(LABPC) ((LABPC)->base + 0x0c)
+
+#define B0DATA(LABPC) ((LABPC)->base + 0x18)
+#define B1DATA(LABPC) ((LABPC)->base + 0x19)
+#define B2DATA(LABPC) ((LABPC)->base + 0x1A)
+#define BMODE(LABPC) ((LABPC)->base + 0x1B)
+
+/* 8255 registers:
+ */
+
+#define PORTX(LABPC, X) ((LABPC)->base + 0x10 + X)
+
+#define PORTA(LABPC) PORTX(LABPC, 0)
+#define PORTB(LABPC) PORTX(LABPC, 1)
+#define PORTC(LABPC) PORTX(LABPC, 2)
+
+#define DCR(LABPC) ((LABPC)->base + 0x13)
+
+extern int labpcattach(struct isa_device *dev);
+extern int labpcdetach(struct isa_device *dev);
+extern int labpcprobe(struct isa_device *dev);
+struct isa_driver labpcdriver =
+ { labpcprobe, labpcattach, "labpc", 0 /* , labpcdetach */ };
+
+static void
+bp_done(struct buf *bp, int err)
+{
+ if (err)
+ {
+ bp->b_error = err;
+ bp->b_flags |= B_ERROR;
+ }
+
+ biodone(bp);
+}
+
+static void tmo_stop(void *p);
+
+static void
+done_and_dequeu(struct ctlr *ctlr, struct buf *bp, int err)
+{
+ static void start(struct ctlr *ctlr);
+
+ bp->b_resid = ctlr->data_end - ctlr->data;
+
+ ctlr->data = 0;
+
+ ctlr->start_queue.b_actf = bp->b_actf;
+ bp_done(bp, err);
+
+ untimeout(tmo_stop, ctlr);
+
+ start(ctlr);
+}
+
+static inline void
+ad_clear(struct ctlr *ctlr)
+{
+ int i;
+ loutb(ADCLEAR(ctlr), 0);
+ for (i = 0; i < 10000 && (inb(STATUS(ctlr)) & GATA0); i++)
+ ;
+ (void)inb(ADFIFO(ctlr));
+ (void)inb(ADFIFO(ctlr));
+}
+
+/* reset: Reset the board following the sequence on page 5-1
+ */
+static inline void
+reset(struct ctlr *ctlr)
+{
+ int s = splhigh();
+
+ CR_CLR(ctlr, 3); /* Turn off interrupts first */
+ splx(s);
+
+ CR_CLR(ctlr, 1);
+ CR_CLR(ctlr, 2);
+ CR_CLR(ctlr, 4);
+
+ loutb(AMODE(ctlr), 0x34);
+ loutb(A0DATA(ctlr),0x0A);
+ loutb(A0DATA(ctlr),0x00);
+
+ loutb(DMATCICLR(ctlr), 0x00);
+ loutb(TICR(ctlr), 0x00);
+
+ ad_clear(ctlr);
+
+ loutb(DAC0L(ctlr), 0);
+ loutb(DAC0H(ctlr), 0);
+ loutb(DAC1L(ctlr), 0);
+ loutb(DAC1H(ctlr), 0);
+
+ ad_clear(ctlr);
+}
+
+static int
+labpc_goaway(struct kern_devconf *kdc, int force)
+{
+ if(force) {
+ dev_detach(kdc);
+ return 0;
+ } else {
+ return EBUSY; /* XXX fix */
+ }
+}
+
+static struct kern_devconf kdc_template = {
+ 0, 0, 0, /* filled in by dev_attach */
+ "labpc", 0, { MDDT_ISA, 0, "tty" },
+ isa_generic_externalize, 0, labpc_goaway, ISA_EXTERNALLEN,
+ &kdc_isa0, /* parent */
+ 0, /* parentdata */
+ DC_UNKNOWN,
+ "?" /* Description (filled in later ) */
+};
+
+static inline void
+labpc_registerdev(struct isa_device *id)
+{
+ struct kern_devconf *kdc = &labpcs[id->id_unit]->kdc;
+ kdc->kdc_unit = id->id_unit;
+ kdc->kdc_parentdata = id;
+ dev_attach(kdc);
+}
+
+/* overrun: slam the start convert register and OVERRUN should get set:
+ */
+static u_char
+overrun(struct ctlr *ctlr)
+{
+ int i;
+
+ u_char status = inb(STATUS(ctlr));
+ for (i = 0; ((status & OVERRUN) == 0) && i < 100; i++)
+ {
+ loutb(ADSTART(ctlr), 1);
+ status = inb(STATUS(ctlr));
+ }
+
+ return status;
+}
+
+static int
+labpcinit(void)
+{
+ if (NLABPC > MAX_UNITS)
+ return 0;
+
+ labpcs = malloc(NLABPC * sizeof(struct ctlr *), M_DEVBUF, M_NOWAIT);
+ if (labpcs)
+ {
+ bzero(labpcs, NLABPC * sizeof(struct cltr *));
+ return 1;
+ }
+ return 0;
+}
+
+int labpcprobe(struct isa_device *dev)
+{
+ static unit;
+ struct ctlr scratch, *ctlr;
+ u_char status;
+
+ if (!labpcs)
+ {
+ if (labpcinit() == 0)
+ {
+ printf("labpcprobe: init failed\n");
+ return 0;
+ }
+ }
+
+ if (unit > NLABPC)
+ {
+ printf("Too many LAB-PCs. Reconfigure O/S.\n");
+ return 0;
+ }
+ ctlr = &scratch; /* Need somebody with the right base for the macros */
+ ctlr->base = dev->id_iobase;
+
+ /* XXX: There really isn't a perfect way to probe this board.
+ * Here is my best attempt:
+ */
+ reset(ctlr);
+
+ /* After reset none of these bits should be set:
+ */
+ status = inb(STATUS(ctlr));
+ if (status & (GATA0 | OVERFLOW | DAVAIL | OVERRUN))
+ return 0;
+
+ /* Now try to overrun the board FIFO and get the overrun bit set:
+ */
+ status = overrun(ctlr);
+
+ if ((status & OVERRUN) == 0) /* No overrun bit set? */
+ return 0;
+
+ /* Assume we have a board.
+ */
+ reset(ctlr);
+
+ if ( (labpcs[unit] = malloc(sizeof(struct ctlr), M_DEVBUF, M_NOWAIT)) )
+ {
+ struct ctlr *l = labpcs[unit];
+
+ bzero(l, sizeof(struct ctlr));
+ l->base = ctlr->base;
+ dev->id_unit = l->unit = unit;
+
+ l->kdc = kdc_template;
+ l->kdc.kdc_state = DC_IDLE;
+
+ if ((status & LABPCPLUS) == 0)
+ l->kdc.kdc_description = "National Instrument's LabPC+";
+ else
+ l->kdc.kdc_description = "National Instrument's LabPC";
+
+ unit++;
+ return 1;
+ }
+ else
+ {
+ printf("labpc%d: Can't malloc.\n", unit);
+ return 0;
+ }
+}
+
+/* attach: Set things in a normal state.
+ */
+int labpcattach(struct isa_device *dev)
+{
+ struct ctlr *ctlr = labpcs[dev->id_unit];
+ ctlr->sample_us = (1000000.0 / (double)LABPC_DEFAULT_HERZ) + .50;
+ reset(ctlr);
+ labpc_registerdev(dev);
+
+ ctlr->dcr_val = 0x80;
+ ctlr->dcr_is = 0x80;
+ loutb(DCR(ctlr), ctlr->dcr_val);
+
+ return 1;
+}
+
+int
+labpcdetach(struct isa_device *id)
+{
+ struct ctlr *ctlr = labpcs[id->id_unit];
+ CR_CLR(ctlr, 3);
+ reset(ctlr);
+ dev_detach(&ctlr->kdc);
+ return 0;
+}
+
+/* Null handlers:
+ */
+static void null_intr (struct ctlr *ctlr) { }
+static void null_start(struct ctlr *ctlr, long count) { }
+static void null_stop (struct ctlr *ctlr) { }
+
+static inline void
+trigger(struct ctlr *ctlr)
+{
+ CR_EXPR(ctlr, 2, |= SWTRIG);
+}
+
+static void
+ad_start(struct ctlr *ctlr, long count)
+{
+ if (!SWTRIGGERRED(ctlr)) {
+ int chan = CHAN(ctlr->dev);
+ CR_EXPR(ctlr, 1, &= ~SCANEN);
+ CR_EXPR(ctlr, 2, &= ~TBSEL);
+
+ MA(ctlr, chan);
+ GAIN(ctlr, ctlr->gains[chan]);
+
+ if (SCAN(ctlr->dev))
+ CR_EXPR(ctlr, 1, |= SCANEN);
+
+ loutb(AMODE(ctlr), 0x34);
+ loutb(A0DATA(ctlr), (u_char)((ctlr->sample_us & 0xff)));
+ loutb(A0DATA(ctlr), (u_char)((ctlr->sample_us >> 8)&0xff));
+ loutb(AMODE(ctlr), 0x70);
+
+ ad_clear(ctlr);
+ trigger(ctlr);
+ }
+
+ ctlr->tmo = ((count + 16) * (long)ctlr->sample_us * hz) / 1000000 + 1;
+}
+
+static void
+ad_interval_start(struct ctlr *ctlr, long count)
+{
+ int chan = CHAN(ctlr->dev);
+ int n_frames = count / (chan + 1);
+
+ if (!SWTRIGGERRED(ctlr)) {
+ CR_EXPR(ctlr, 1, &= ~SCANEN);
+ CR_EXPR(ctlr, 2, &= ~TBSEL);
+
+ MA(ctlr, chan);
+ GAIN(ctlr, ctlr->gains[chan]);
+
+ /* XXX: Is it really possible that you clear INTSCAN as
+ * the documentation says? That seems pretty unlikely.
+ */
+ CR_EXPR(ctlr, 4, &= ~INTSCAN); /* XXX: Is this possible? */
+
+ /* Program the sample interval counter to run as fast as
+ * possible.
+ */
+ loutb(AMODE(ctlr), 0x34);
+ loutb(A0DATA(ctlr), (u_char)(0x02));
+ loutb(A0DATA(ctlr), (u_char)(0x00));
+ loutb(AMODE(ctlr), 0x70);
+
+ /* Program the interval scanning counter to run at the sample
+ * frequency.
+ */
+ loutb(BMODE(ctlr), 0x74);
+ loutb(B1DATA(ctlr), (u_char)((ctlr->sample_us & 0xff)));
+ loutb(B1DATA(ctlr), (u_char)((ctlr->sample_us >> 8)&0xff));
+ CR_EXPR(ctlr, 1, |= SCANEN);
+
+ ad_clear(ctlr);
+ trigger(ctlr);
+ }
+
+ /* Each frame time takes two microseconds per channel times
+ * the number of channels being sampled plus the sample period.
+ */
+ ctlr->tmo = ((n_frames + 16) *
+ ((long)ctlr->sample_us + (chan + 1 ) * 2 ) * hz) / 1000000 + 1;
+}
+
+static void
+all_stop(struct ctlr *ctlr)
+{
+ reset(ctlr);
+}
+
+static void
+tmo_stop(void *p)
+{
+ struct ctlr *ctlr = (struct ctlr *)p;
+ struct buf *bp;
+ int s = spltty();
+
+ if (ctlr == 0)
+ {
+ printf("labpc?: Null ctlr struct?\n");
+ return;
+ }
+
+ printf("labpc%d: timeout\n", ctlr->unit);
+
+ (*ctlr->stop)(ctlr);
+
+ bp = ctlr->start_queue.b_actf;
+
+ if (bp == 0) {
+ printf("labpc%d timeout: Null bp.\n", ctlr->unit);
+
+ /* No more data being transferred.
+ */
+ return;
+ }
+
+ done_and_dequeu(ctlr, bp, ETIMEDOUT);
+ splx(s);
+}
+
+static void ad_intr(struct ctlr *ctlr)
+{
+ u_char status;
+
+ while ( (status = (inb(STATUS(ctlr)) & (DAVAIL|OVERRUN|OVERFLOW)) ) )
+ {
+ if ((status & (OVERRUN|OVERFLOW)))
+ {
+ struct buf *bp = ctlr->start_queue.b_actf;
+
+ printf("ad_intr: error: data %p, status %x",
+ ctlr->data, status);
+
+ if (status & OVERRUN)
+ printf(" OVERRUN");
+
+ if (status & OVERFLOW)
+ printf(" OVERFLOW");
+
+ printf("\n");
+
+ (*ctlr->stop)(ctlr);
+
+ /* There may not be a bp if the interrupt went off between
+ * frames, that is, when no process was ready to receive and
+ * we are using a mode that is driven by the sample clock.
+ */
+ if (bp)
+ {
+ done_and_dequeu(ctlr, bp, EIO);
+ return;
+ }
+ else
+ ctlr->err = status; /* Set overrun condition */
+ }
+ else /* FIFO interrupt */
+ {
+ if (ctlr->data)
+ {
+ *ctlr->data++ = inb(ADFIFO(ctlr));
+ if (ctlr->data == ctlr->data_end) /* Normal completion */
+ {
+ struct buf *bp = ctlr->start_queue.b_actf;
+
+ done_and_dequeu(ctlr, bp, 0);
+ return;
+ }
+ }
+ else /* Interrupt with no where to put the data. */
+ {
+ (void)inb(ADFIFO(ctlr));
+ ctlr->err = DROPPED_INPUT;
+ return;
+ }
+ }
+ }
+}
+
+void labpcintr(int unit)
+{
+ struct ctlr *ctlr = labpcs[unit];
+ (*ctlr->intr)(ctlr);
+}
+
+/* mode_change_needed: Return whether or not we can open again, or
+ * if the new mode is inconsistent with an already opened mode.
+ * We only permit multiple opens for digital I/O now.
+ */
+
+static int
+mode_change_needed(dev_t current, dev_t next)
+{
+ return ! (DIGITAL(current) && DIGITAL(next));
+}
+
+int
+labpcopen(dev_t dev, int flags, int fmt, struct proc *p)
+{
+ u_short unit = UNIT(dev);
+
+ struct ctlr *ctlr;
+
+ if (unit >= MAX_UNITS)
+ return ENXIO;
+
+ ctlr = labpcs[unit];
+
+ if (ctlr == 0)
+ return ENXIO;
+
+ /* Don't allow another open if we have to change modes.
+ */
+
+ if ( (ctlr->flags & BUSY) == 0)
+ {
+ ctlr->flags |= BUSY;
+ ctlr->kdc.kdc_state = DC_BUSY;
+
+ reset(ctlr);
+
+ ctlr->err = 0;
+ ctlr->dev = dev;
+
+ ctlr->intr = null_intr;
+ ctlr->starter = null_start;
+ ctlr->stop = null_stop;
+
+ CR_EXPR(ctlr, 3, |= ERRINTEN);
+ }
+ else if (mode_change_needed(ctlr->dev, dev))
+ return EBUSY;
+
+ return 0;
+}
+
+int
+labpcclose(dev_t dev, int flags, int fmt, struct proc *p)
+{
+ struct ctlr *ctlr = labpcs[UNIT(dev)];
+
+ (*ctlr->stop)(ctlr);
+
+ ctlr->kdc.kdc_state = DC_IDLE;
+ ctlr->flags &= ~BUSY;
+
+ return 0;
+}
+
+/* Start: Start a frame going in or out.
+ */
+static void
+start(struct ctlr *ctlr)
+{
+ struct buf *bp;
+
+ if ((bp = ctlr->start_queue.b_actf) == 0)
+ {
+ /* We must turn off FIFO interrupts when there is no
+ * place to put the data. We have to get back to
+ * reading before the FIFO overflows.
+ */
+ CR_EXPR(ctlr, 3, &= ~FIFOINTEN);
+ ctlr->start_queue.b_active = 0;
+ return;
+ }
+
+ ctlr->data = (u_char *)bp->b_un.b_addr;
+ ctlr->data_end = ctlr->data + bp->b_bcount;
+
+ if (!FIFOINTENABLED(ctlr)) /* We can store the data again */
+ {
+ if (ctlr->err) /* Dropped input between records */
+ {
+ done_and_dequeu(ctlr, bp, ENOSPC);
+ return;
+ }
+ CR_EXPR(ctlr, 3, |= FIFOINTEN);
+ }
+ ctlr->err = 0;
+
+ (*ctlr->starter)(ctlr, bp->b_bcount);
+
+ timeout(tmo_stop, ctlr, ctlr->tmo);
+}
+
+static void
+ad_strategy(struct buf *bp, struct ctlr *ctlr)
+{
+ int s;
+
+ s = spltty();
+ bp->b_actf = NULL;
+
+ if (ctlr->start_queue.b_active)
+ {
+ ctlr->last->b_actf = bp;
+ ctlr->last = bp;
+ }
+ else
+ {
+ ctlr->start_queue.b_active = 1;
+ ctlr->start_queue.b_actf = bp;
+ ctlr->last = bp;
+ start(ctlr);
+ }
+ splx(s);
+}
+
+/* da_strategy: Send data to the D-A. The CHAN field should be
+ * 0: D-A port 0
+ * 1: D-A port 1
+ * 2: Alternate port 0 then port 1
+ *
+ * XXX:
+ *
+ * 1. There is no state for CHAN field 2:
+ * the first sample in each buffer goes to channel 0.
+ *
+ * 2. No interrupt support yet.
+ */
+void da_strategy(struct buf *bp, struct ctlr *ctlr)
+{
+ int len;
+ u_char *data;
+ int port;
+ int i;
+
+ switch(CHAN(bp->b_dev))
+ {
+ case 0:
+ port = DAC0L(ctlr);
+ break;
+
+ case 1:
+ port = DAC1L(ctlr);
+ break;
+
+ case 2: /* Device 2 handles both ports interleaved. */
+ if (bp->b_bcount <= 2)
+ {
+ port = DAC0L(ctlr);
+ break;
+ }
+
+ len = bp->b_bcount / 2;
+ data = (u_char *)bp->b_un.b_addr;
+
+ for (i = 0; i < len; i++)
+ {
+ loutb(DAC0H(ctlr), *data++);
+ loutb(DAC0L(ctlr), *data++);
+ loutb(DAC1H(ctlr), *data++);
+ loutb(DAC1L(ctlr), *data++);
+ }
+
+ bp->b_resid = bp->b_bcount & 3;
+ bp_done(bp, 0);
+ return;
+
+ default:
+ bp_done(bp, ENXIO);
+ return;
+ }
+
+ /* Port 0 or 1 falls through to here.
+ */
+ if (bp->b_bcount & 1) /* Odd transfers are illegal */
+ bp_done(bp, EIO);
+
+ len = bp->b_bcount;
+ data = (u_char *)bp->b_un.b_addr;
+
+ for (i = 0; i < len; i++)
+ {
+ loutb(port + 1, *data++);
+ loutb(port, *data++);
+ }
+
+ bp->b_resid = 0;
+
+ bp_done(bp, 0);
+}
+
+/* Input masks for MODE 0 of the ports treating PC as a single
+ * 8 bit port. Set these bits to set the port to input.
+ */
+ /* A B lowc highc combined */
+static u_char set_input[] = { 0x10, 0x02, 0x01, 0x08, 0x09 };
+
+static void flush_dcr(struct ctlr *ctlr)
+{
+ if (ctlr->dcr_is != ctlr->dcr_val)
+ {
+ loutb(DCR(ctlr), ctlr->dcr_val);
+ ctlr->dcr_is = ctlr->dcr_val;
+ }
+}
+
+/* do: Digital output
+ */
+static void
+digital_out_strategy(struct buf *bp, struct ctlr *ctlr)
+{
+ int len;
+ u_char *data;
+ int port;
+ int i;
+ int chan = CHAN(bp->b_dev);
+
+ ctlr->dcr_val &= ~set_input[chan]; /* Digital out: Clear bit */
+ flush_dcr(ctlr);
+
+ port = PORTX(ctlr, chan);
+
+ len = bp->b_bcount;
+ data = (u_char *)bp->b_un.b_addr;
+
+ for (i = 0; i < len; i++)
+ {
+ loutb(port, *data++);
+ }
+
+ bp->b_resid = 0;
+
+ bp_done(bp, 0);
+}
+
+/* digital_in_strategy: Digital input
+ */
+static void
+digital_in_strategy(struct buf *bp, struct ctlr *ctlr)
+{
+ int len;
+ u_char *data;
+ int port;
+ int i;
+ int chan = CHAN(bp->b_dev);
+
+ ctlr->dcr_val |= set_input[chan]; /* Digital in: Set bit */
+ flush_dcr(ctlr);
+ port = PORTX(ctlr, chan);
+
+ len = bp->b_bcount;
+ data = (u_char *)bp->b_un.b_addr;
+
+ for (i = 0; i < len; i++)
+ {
+ *data++ = inb(port);
+ }
+
+ bp->b_resid = 0;
+
+ bp_done(bp, 0);
+}
+
+
+void
+labpcstrategy(struct buf *bp)
+{
+ struct ctlr *ctlr = labpcs[UNIT(bp->b_dev)];
+
+ if (DIGITAL(bp->b_dev)) {
+ if (bp->b_flags & B_READ) {
+ ctlr->starter = null_start;
+ ctlr->stop = all_stop;
+ ctlr->intr = null_intr;
+ digital_in_strategy(bp, ctlr);
+ }
+ else
+ {
+ ctlr->starter = null_start;
+ ctlr->stop = all_stop;
+ ctlr->intr = null_intr;
+ digital_out_strategy(bp, ctlr);
+ }
+ }
+ else {
+ if (bp->b_flags & B_READ) {
+
+ ctlr->starter = INTERVAL(ctlr->dev) ? ad_interval_start : ad_start;
+ ctlr->stop = all_stop;
+ ctlr->intr = ad_intr;
+ ad_strategy(bp, ctlr);
+ }
+ else
+ {
+ ctlr->starter = null_start;
+ ctlr->stop = all_stop;
+ ctlr->intr = null_intr;
+ da_strategy(bp, ctlr);
+ }
+ }
+}
+
+int
+labpcioctl(dev_t dev, int cmd, caddr_t arg, int mode, struct proc *p)
+{
+ struct ctlr *ctlr = labpcs[UNIT(dev)];
+
+ switch(cmd)
+ {
+ case AD_MICRO_PERIOD_SET:
+ {
+ /* XXX I'm only supporting what I have to, which is
+ * no slow periods. You can't get any slower than 15 Hz
+ * with the current setup. To go slower you'll need to
+ * support TCINTEN in CR3.
+ */
+
+ long sample_us = *(long *)arg;
+
+ if (sample_us > 65535)
+ return EIO;
+
+ ctlr->sample_us = sample_us;
+ return 0;
+ }
+
+ case AD_MICRO_PERIOD_GET:
+ *(long *)arg = ctlr->sample_us;
+ return 0;
+
+ case AD_NGAINS_GET:
+ *(int *)arg = 8;
+ return 0;
+
+ case AD_NCHANS_GET:
+ *(int *)arg = 8;
+ return 0;
+
+ case AD_SUPPORTED_GAINS:
+ {
+ static double gains[] = {1., 1.25, 2., 5., 10., 20., 50., 100.};
+ copyout(gains, *(caddr_t *)arg, sizeof(gains));
+
+ return 0;
+ }
+
+ case AD_GAINS_SET:
+ {
+ copyin(*(caddr_t *)arg, ctlr->gains, sizeof(ctlr->gains));
+ return 0;
+ }
+
+ case AD_GAINS_GET:
+ {
+ copyout(ctlr->gains, *(caddr_t *)arg, sizeof(ctlr->gains));
+ return 0;
+ }
+
+ default:
+ return ENOTTY;
+ }
+}
OpenPOWER on IntegriCloud