Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 15 Nov 1997 12:06:09 -0800 (PST)
From:      jamil@trojanhorse.ml.org
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   i386/5058: New Driver: aiox - Industrial Computer Source AIO-P Analog board
Message-ID:  <199711152006.MAA07024@trojanhorse.ml.org>
Resent-Message-ID: <199711152010.MAA11482@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         5058
>Category:       i386
>Synopsis:       Driver for Low Cost ISA, 12Bit Analog Input Board
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sat Nov 15 12:10:01 PST 1997
>Last-Modified:
>Originator:     Jamil J. Weatherbee
>Organization:
>Release:        FreeBSD 2.2.5-STABLE i386
>Environment:

i386 FreeBSD environment with ISA bus and AIO8-P Analog Card

>Description:

Allows efficient interrupt driven use of the above board
see http://www.indcompsrc.com/products/data/html/aio8g-p.html
 &  http://www.indcompsrc.com/products/data/html/at16-p.html

>How-To-Repeat:

See Environment section above.

>Fix:

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	Makefile
#	aiox.4
#	aiox.c
#	aioxioctl.h
#
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
X# Make file to install the aiox driver files in their proper places
X
Xinstall:
X	install -c -o root -g wheel -m 0644 aiox.c /sys/i386/isa
X	install -c -o root -g bin -m 0644 aioxioctl.h /sys/sys
X	install -c -o bin -g bin -m 0444 aioxioctl.h /usr/include/sys
X	install -c -o bin -g bin -m 444 aiox.4 /usr/share/man/man4/
X	gzip -f /usr/share/man/man4/aiox.4
X	install -c -o bin -g bin -m 444 aiox.4 /usr/share/man/man4/i386/
X	gzip -f /usr/share/man/man4/i386/aiox.4
END-of-Makefile
echo x - aiox.4
sed 's/^X//' >aiox.4 << 'END-of-aiox.4'
X.\"
X.\" Copyright (c) 1997 Jamil J. Weatherbee
X.\" All rights reserved.
X.\"
X.\" 
X.\" Redistribution and use in source and binary forms, with or without
X.\" modification, are permitted provided that the following conditions
X.\" are met:
X.\" 1. Redistributions of source code must retain the above copyright
X.\"    notice, this list of conditions and the following disclaimer
X.\"    in this position and unchanged.
X.\" 2. Redistributions in binary form must reproduce the above copyright
X.\"    notice, this list of conditions and the following disclaimer in the
X.\"    documentation and/or other materials provided with the distribution.
X.\" 3. The name of the author may not be used to endorse or promote products
X.\"    derived from this software without specific prior written permission
X.\" 
X.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
X.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
X.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
X.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
X.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
X.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
X.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
X.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
X.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
X.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X.\"
X.\" Industrial Computer Source model AIO8-P
X.\" 8 channel, moderate speed analog to digital converter board with
X.\" 128 channel MUX capability via daisy chained AT-16P units
X.\" aiox.c, character device driver, last revised November 14 1997
X.\" See http://www.indcompsrc.com/products/data/html/aio8g-p.html
X.\"
X.\" Written by: Jamil J. Weatherbee <jamil@trojanhorse.ml.org>
X.\"
X.\"
X.Dd November 14, 1997
X.Dt AIOX 4 i386
X.Os FreeBSD
X.Sh NAME
X.Nm aiox
X.Nd
XIndustrial Computer Source AIO8-P driver
X.Sh SYNOPSIS
X.Cd "device aiox0 at isa? port 0x260 tty irq 5 vector aioxintr"
X.Sh DESCRIPTION
XThis driver supports the Industrial Computer Source \fIAIO8-P 8-Channel
X12-Bit Analog Input board\fP.
X.Pp
XThis board provides 8 12 bit, single-ended analog input ports.
XThe driver also directly provides support for up to 8 daisy chained 
X\fIAT16-P Programmable Analog Multiplexers with 16 Differential Inputs\fP.
XThis makes it possible to sample up to 128 differential channels with a single
Xinterface board.  
XUse of at least one \fIAT16-P\fP is highly recommended as the \fIAIO8-P\fP
Xoffers no signal conditioning options and only operates in a -5 to +5 Volt
Xinput range.  However, if you wish to use the \fIAIO8-P\fP standalone,
Xinsert the following into your kernel
X.Xr config 8
Xfile:
X.Bd -literal -offset indent
Xoptions  AIOX_CHANNELS=8
X.Ed
X.Pp
XSelection of the input port is through the minor number:
X.Pp
X.Bd -literal -offset indent
XThe 9 bit minor number format is UUCCCCMMM, where
X  UU: board unit (0-3)
XCCCC: external multiplexer channel (0-15) (on AT-16P units) 
X MMM: internal multiplexer channel (0-7) (on AIO8-P card)
X.Ed
X.Pp
X.Xr devfs 5
Xdevice node names are of the form: aiox[0-3][a-p][0-7] 
X.Pp
X.Sh IOCTL
XThe following
X.Xr ioctl 2
Xcalls apply to
X.Nm
Xdevices.  Their declaration can be found in the header files
X.Pa <sys/aioxioctl.h>
Xand
X.Pa <sys/dataacq.h>
X.Bl -tag -width AD_MICRO_PERIOD_SET
X.It Dv AD_MICRO_PERIOD_SET
XTakes a pointer to a long argument specifying the number of microseconds
Xbetween samples.  Half of this is used as the external multiplexer
Xsettling time and the other half as conversion time.
X.It Dv AD_MICRO_PERIOD_GET
XTakes a pointer to a long argument and returns the current number of
Xmicroseconds between samples.
X.It Dv AD_START
XStarts the clocked accumulation of sample values into a channels driver fifo.
XWhen a channel is first opened its software fifo is initialized in the
Xstopped state.  This is to prevent high sample clocks from overrunning the
Xfifos before the user is ready to read from the channel.    
X.It Dv AD_STOP
XStops the clocked accumulation of sample values into a channels driver fifo.
X.Sh BUGS
XOn the \fIAIO8-P\fP, interrupt driven conversion (the only type
Xsupported by the
X.Nm
Xdriver) is facilitated through 8253 timer #2.  In order for interrrupts to
Xbe generated you must connect line 6 to line 24 (counter 2 output to
Xinterrupt input) and line 23 to line 29 (counter 2 gate to +5VDC).
XDue to the design of the \fIAIO8-P\fP this precludes the use of programmable
Xgain control.    
X.Pp
XA 64 entry (128 byte) software fifo is provided for each analog channel.
XReads are non-blocking on the
X.Nm
Xdriver, so providing a 
X.Xr read 2
Xbuffer larger than the software fifo is unnecessary. 
X.Pp
XUse 
X.Xr select 2
Xwherever possible, especially with large numbers of open channels.
XUsing this method, multichannel sample rates as high as 16,000 samples/sec
Xhave been observed.
X.Pp
XSample rates lower than 32 Hz are not supported.
X.Sh SEE ALSO
X.Bd -literal
Xhttp://www.indcompsrc.com/products/data/html/aio8g-p.html
Xhttp://www.indcompsrc.com/products/data/html/at16-p.html
X.Ed
X.Sh AUTHOR
XJamil J. Weatherbee <jamil@trojanhorse.ml.org>.
END-of-aiox.4
echo x - aiox.c
sed 's/^X//' >aiox.c << 'END-of-aiox.c'
X/*
X * Copyright (c) 1997 Jamil J. Weatherbee
X * All rights reserved.
X *
X * 
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer
X *    in this position and unchanged.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. The name of the author may not be used to endorse or promote products
X *    derived from this software without specific prior written permission
X * 
X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
X * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
X * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
X * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
X * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
X * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
X * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
X * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X *
X * Industrial Computer Source model AIO8-P
X * 8 channel, moderate speed analog to digital converter board with
X * 128 channel MUX capability via daisy chained AT-16P units
X * aiox.c, character device driver, last revised November 14 1997
X * See http://www.indcompsrc.com/products/data/html/aio8g-p.html
X *     http://www.indcompsrc.com/products/data/html/at16-p.html
X *
X * Written by: Jamil J. Weatherbee <jamil@trojanhorse.ml.org>
X *
X */
X
X
X/* Include Files */
X
X#include "aiox.h"
X#if NAIOX > 0
X
X#include <sys/param.h> 
X#include <sys/systm.h>
X#include <sys/proc.h>
X#include <sys/kernel.h>
X#include <sys/conf.h>
X#include <sys/fcntl.h>
X#include <sys/malloc.h>
X#include <sys/buf.h> 
X#include <machine/clock.h>
X#include <i386/isa/isa.h>
X#include <i386/isa/isa_device.h>
X#include <sys/aioxioctl.h>
X#include <sys/dataacq.h>
X
X#ifdef DEVFS
X#include <sys/devfsext.h>
X#endif 
X
X/* Local Defines */
X
X#define CDEV_MAJOR 85
X#define NUMPORTS 8
X
X#define ADLOW 0x0
X#define ADHIGH 0x1
X#define STATUS 0x2
X#define CNTR0 0x4
X#define CNTR1 0x5
X#define CNTR2 0x6
X#define CNTRCNTRL 0x7
X
X#define DEVFORMAT "aiox%d%c%d"
X#define CLOCK2FREQ 4.165
X#define MAX_MICRO_PERIOD (65535/CLOCK2FREQ*PRIMARY_STATES)
X#define MIN_MICRO_PERIOD 25
X#define DEFAULT_MICRO_PERIOD MAX_MICRO_PERIOD
X
X#define PRIMARY_STATES 2  /* Setup and conversion are clock tick consuming */
X#define STATE_SETUP 0
X#define STATE_CONVERT 1
X#define STATE_READ 2
X
X/* Notes on interrupt driven A/D conversion:
X * On the AIO8-P, interrupt driven conversion (the only type supported by this
X * driver) is facilitated through 8253 timer #2.  In order for interrrupts to
X * be generated you must connect line 6 to line 24 (counter 2 output to 
X * interrupt input) and line 23 to line 29 (counter 2 gate to +5VDC). 
X * Due to the design of the AIO8-P this precludes the use of programmable 
X * gain control.
X */
X
X/* mode bits for the status register */
X
X#define EOC 0x80 
X#define IEN 0x08  
X#define IMUXMASK 0x07
X#define EMUXMASK 0xf0
X
X/* mode bits for counter controller */
X
X#define LD2MODE4 0xb8
X
X/* Minor allocations:
X * UUCCCCMMM
X * UU: board unit (0-3) 
X * CCCC: external multiplexer channel (0-15) (on AT-16P units)
X * MMM: internal multiplexer channel (0-7) (on AIO8-P card)
X */
X
X#define FIFOSIZE 65 /* one entry always unused */
X#define MAXUNITS 4
X#define NUMIMUXES 8
X
X#ifdef AIOX_CHANNELS 
X#define NUMCHANNELS AIOX_CHANNELS
X#else
X#define NUMCHANNELS 128
X#endif
X
X#define UNIT(dev) ((minor(dev) & 0x180) >> 7)
X#define CHANNEL(dev) (minor(dev) & 0x7f) 
X#define EMUX(chan) ((chan & 0x78) >> 3)
X#define EMUXMAKE(chan) ((chan & 0x78) << 1)
X#define IMUX(chan) (chan & 0x07)
X#define LMINOR(unit, chan) ((unit << 7)+chan)
X
X/* port statuses */
X
X#define STATUS_UNUSED 0 
X#define STATUS_INUSE 1
X#define STATUS_STOPPED 2
X
X/* Type definitions */
X
Xtypedef struct
X{
X  short status; /* the status of this chan */
X  struct selinfo readselect; /* the select() polling info */
X  u_short fifo[FIFOSIZE]; /* fifo for this chan */
X  int fifostart, fifoend; /* the ptrs showing where info is stored in fifo */
X  void *devfs_token; /* the devfs token for this chan */
X  int nextchan;  
X} taiox_chan;
X
Xtypedef struct 
X{ 
X  struct isa_device *isaunit; /* ptr to isa device information */     
X  taiox_chan chan[NUMCHANNELS]; /* the device nodes */
X  int curchan; /* the current chan being intr handled */
X  int firstchan; /* the first chan to go to in list */
X  int state; /* is the node in setup or convert mode */ 
X  long microperiod; /* current microsecond period setting */ 
X  u_char perlo, perhi; /* current values to send to clock 2 after every intr */
X   
X} taiox_unit;
X
X/* Function Prototypes */
X
Xstatic int aiox_probe (struct isa_device *idp);  /* Check for aiox board */
Xstatic int aiox_attach (struct isa_device *idp);  /* Take aiox board */
Xstatic int sync_clock2 (int unit, long period); /* setup clock 2 period */
Xstatic __inline int getfifo (taiox_chan *pchan, u_short *fifoent);
Xstatic __inline int putfifo (taiox_chan *pchan, u_short fifoent);
Xstatic int aiox_open (dev_t dev, int oflags, int devtype, struct proc *p);
Xstatic int aiox_close (dev_t dev, int fflag, int devtype, struct proc *p);
Xstatic int aiox_ioctl (dev_t dev, int cmd, caddr_t data,
X		        int fflag, struct proc *p);
Xstatic int aiox_read (dev_t dev, struct uio *uio, int ioflag);
Xstatic int aiox_select (dev_t dev, int which, struct proc *p);
Xstatic void aiox_strategy (struct buf *bp);
X
X
X/* Global Data */
X
Xstatic int aiox_devsw_installed = 0;  /* Protect against reinit multiunit */
Xstatic taiox_unit *aiox_unit[NAIOX]; /* data structs for each unit */ 
X
X/* Character device switching structure */
Xstatic struct cdevsw aiox_cdevsw = { aiox_open, aiox_close, rawread, nowrite,
X                                     aiox_ioctl, nostop, noreset, nodevtotty,
X                                     aiox_select, nommap, aiox_strategy,"aiox",
X                                     NULL, -1 };
X
X/* Structure expected to tell how to probe and attach the driver
X * Must be published externally (cannot be static) */
Xstruct isa_driver aioxdriver = { aiox_probe, aiox_attach, "aiox", 0 };
X
X
X/* handle the ioctls */
Xstatic int aiox_ioctl (dev_t dev, int cmd, caddr_t data,
X		        int fflag, struct proc *p)
X{
X  int unit = UNIT(dev);
X  int chan = CHANNEL(dev);
X  taiox_unit *info = aiox_unit[unit];
X  int s;
X   
X  switch (cmd)
X   {  
X    case AD_STOP: s = spltty();
X                  info->chan[chan].status = STATUS_STOPPED;              
X                  splx(s);
X                  return 0;
X      
X    case AD_START: s = spltty();
X                   info->chan[chan].status = STATUS_INUSE;
X                   splx(s);
X                   return 0;
X
X    case AD_MICRO_PERIOD_SET: 
X                   s = spltty();
X                   if (sync_clock2 (unit, *(long *) data))
X	            {          
X                      splx(s);
X		      return EPERM;
X                    }
X                   splx(s);
X                   return 0;
X      
X    case AD_MICRO_PERIOD_GET: *(long *) data = info->microperiod;
X                              return 0;    
X   }
X   
X  return ENOTTY;  
X}
X
X
X/* handle select() based read polling */
Xstatic int aiox_select (dev_t dev, int which, struct proc *p)
X{
X  int unit = UNIT(dev);
X  int chan = CHANNEL(dev);
X  taiox_unit *info = aiox_unit[unit];
X  int s;
X   
X  s = spltty();
X  if (which == FREAD)
X   if (info->chan[chan].fifostart != info->chan[chan].fifoend)
X    { 
X      splx(s);
X      return 1; /* ready for read */
X    }
X   else    
X    {
X      /* record this request */
X      selrecord (p, &(info->chan[chan].readselect));
X      splx(s);
X      return 0; /* not ready, yet */
X    }
X     
X  splx(s);
X  return 0; /* not ready (any I never will be) */
X}
X
X
X/* how to read from the board */
Xstatic void aiox_strategy (struct buf *bp)
X{
X  int unit = UNIT(bp->b_dev);
X  int chan = CHANNEL(bp->b_dev);
X  taiox_unit *info = aiox_unit[unit];
X  int bufsz = bp->b_bcount / sizeof(u_short);
X  int nread = 0; /* no fifo entries read as of yet */
X  u_short *data = (u_short *) bp->b_un.b_addr; 
X  int s;
X   
X  if (bp->b_flags & B_READ)
X   {
X      s = spltty();
X   
X      while (nread < bufsz)
X       {
X	 if (getfifo (&(info->chan[chan]), data)) break; /* fifo empty ? */
X	 data++; 
X	 nread++;
X       }
X
X      splx(s);		       
X   }
X  
X  bp->b_resid = bp->b_bcount - (nread*sizeof(u_short));
X  biodone (bp); /* done with this buffer */
X}
X
X
X/* open a channel */
Xstatic int aiox_open (dev_t dev, int oflags, int devtype, struct proc *p)
X{
X  int unit = UNIT(dev); /* get unit no */
X  int chan = CHANNEL(dev); /* get channel no */
X  taiox_unit *info; 
X  int s; /* priority */
X  int cur;
X   
X  if ((unit >= NAIOX) || (unit >= MAXUNITS) || (chan >= NUMCHANNELS))
X      return ENXIO; /* unit and channel no ok ? */
X  if (!aiox_unit[unit]) return ENXIO; /* unit attached */
X  info = aiox_unit[unit]; /* ok, this is valid now */
X  
X  if (info->chan[chan].status) return EBUSY; /* channel busy */
X  if (oflags & FREAD)
X   {
X     s=spltty();
X     info->chan[chan].status = STATUS_STOPPED; /* channel open & stopped */
X     info->chan[chan].fifostart = info->chan[chan].fifoend = 0;/* fifo empty */
X     if (info->firstchan < 0) /* if empty chain */
X      {
X	info->firstchan = info->curchan = chan; /* rev up the list */
X	info->chan[chan].nextchan = -1; /* end of the list */
X      }
X     else /* non empty list must insert */
X      {	 
X	if (chan < info->firstchan) /* this one must become first in list */
X	 {
X	   info->chan[chan].nextchan = info->firstchan;
X	   info->firstchan = chan;  
X	 }
X 	else /* insert this one as second - last in chan list */
X	 {
X	   cur = info->firstchan;
X	    
X	   /* traverse list as long as cur is less than chan and cur is
X	    * not last in list */
X	   while ((info->chan[cur].nextchan < chan) && 
X	           (info->chan[cur].nextchan >= 0))
X	     cur = info->chan[cur].nextchan; 
X	   
X	   /* now cur should point to the entry right before yours */
X	   info->chan[chan].nextchan = info->chan[cur].nextchan;
X	   info->chan[cur].nextchan = chan; /* insert yours in */
X	 }
X      }
X     splx(s); 
X     return 0; /* open successful */  
X   }
X  return EPERM; /* this is a read only device */ 
X}
X
X
X/* close a channel */
Xstatic int aiox_close (dev_t dev, int fflag, int devtype, struct proc *p)
X{
X  int unit = UNIT(dev);
X  int chan = CHANNEL(dev);
X  taiox_unit *info = aiox_unit[unit];
X  int s;
X  int cur; 
X   
X  s = spltty();
X  info->chan[chan].status = STATUS_UNUSED; 
X  
X  /* what if we are in the middle of a conversion ?
X   * then smoothly get us out of it: */
X  if (info->curchan == chan)
X   { /* if we are last in list set curchan to first in list */
X     if ((info->curchan = info->chan[chan].nextchan) < 0)
X      info->curchan = info->firstchan;
X
X     info->state = STATE_SETUP;
X   }
X   
X  /* if this is the first channel, then make the second channel the first
X   * channel (note that if this is also the only channel firstchan becomes
X   * -1 and so the list is marked as empty */
X   
X  if (chan == info->firstchan) 
X   info->firstchan = info->chan[chan].nextchan;
X  else /* ok, so there must be at least 2 channels (and it is not the first) */
X   {  
X     cur = info->firstchan;
X
X     /* find the entry before it (which must exist if you are closing) */ 
X     while (info->chan[cur].nextchan < chan) 
X	cur = info->chan[cur].nextchan;
X     /* at this point we must have the entry before ours */
X     info->chan[cur].nextchan = info->chan[chan].nextchan; /* give our link */       
X   
X   }
X  
X  splx(s);
X   
X  return 0; /* close always successful */
X}
X
X
X/* The probing routine - returns number of bytes needed */
Xstatic int aiox_probe (struct isa_device *idp)
X{
X  int unit = idp->id_unit;  /* this device unit number */
X  int iobase = idp->id_iobase; /* the base address of the unit */
X  int addr; 
X   
X  if ((unit < 0) || (unit >= NAIOX) || (unit >= MAXUNITS))
X   { 
X     printf ("aiox: invalid unit number (%d)\n", unit);
X     return 0;
X   }
X   
X  /* the unit number is ok, lets check if used */
X  if (aiox_unit[unit]) 
X   {
X     printf ("aiox: unit (%d) already attached\n", unit);
X     return 0;
X   }
X
X  if (inb (iobase+STATUS) & EOC) return 0; /* End of conv bit should be 0 */
X  for (addr=0; addr<NUMIMUXES; addr++)
X   {
X     outb (iobase+STATUS, EMUXMASK|addr);/* output ones to upper nibbl+addr */ 
X     /* get back a zero in MSB and the addr where you put it */
X     if ((inb (iobase+STATUS) & (EOC|IMUXMASK)) != addr) return 0;
X   }
X 
X  return NUMPORTS; /* this device needs this many ports */ 
X}
X
X/* setup the info structure correctly for reloading clock 2 after interrupt */
Xstatic int sync_clock2 (int unit, long period)
X{
X  int clockper;
X  taiox_unit *info = aiox_unit[unit];
X   
X  if ((period > MAX_MICRO_PERIOD) || (period < MIN_MICRO_PERIOD))
X     return -1; /* error period too long */
X  info->microperiod = period; /* record the period */   
X  clockper = (CLOCK2FREQ * period) / PRIMARY_STATES;
X  info->perlo = clockper & 0xff; /* least sig byte of clock period */
X  info->perhi = ((clockper & 0xff00) >> 8); /* most sig byte of clock period */
X  return 0;
X}
X
X/* The attachment routine - returns true on success */
Xstatic int aiox_attach (struct isa_device *idp)
X{
X  int unit = idp->id_unit;  /* this device unit number */   
X  int iobase = idp->id_iobase; /* the base address of the unit */ 
X  taiox_unit *info; /* pointer to driver specific info for unit */
X  int chan; /* the channel used for creating devfs nodes */
X   
X  if (!(info = malloc(sizeof(*info), M_DEVBUF, M_NOWAIT)))
X   {
X     printf ("aiox%d: cannot allocate driver storage\n", unit);
X     return 0;
X   }
X  aiox_unit[unit] = info; /* make sure to save the pointer */
X  bzero (info, sizeof(*info)); /* clear info structure to all false */
X  info->isaunit = idp;  /* store ptr to isa device information */
X  sync_clock2 (unit, DEFAULT_MICRO_PERIOD); /* setup perlo and perhi */ 
X  info->firstchan = -1; /* channel lists are empty */
X   
X  /* insert devfs nodes */
X  
X#ifdef DEVFS   
X  for (chan=0; chan<NUMCHANNELS; chan++)
X    info->chan[chan].devfs_token = 
X     devfs_add_devswf(&aiox_cdevsw, LMINOR(unit, chan), DV_CHR,
X	              UID_ROOT, GID_WHEEL, 0600, DEVFORMAT,
X		        unit, 'a'+EMUX(chan), IMUX(chan));
X#endif   
X
X  aioxintr (unit); /* start the periodic interrupting process */    
X  return 1; /* obviously successful */
X}
X
X/* Unit interrupt handling routine (interrupts generated by clock 2) */
Xvoid aioxintr (int unit)
X{
X  taiox_unit *info = aiox_unit[unit];
X  int iobase = info->isaunit->id_iobase;
X  u_short fifoent;
X   
X   
X  if (info->firstchan >= 0) /* ? is there even a chan list to traverse */
X   switch (info->state)
X    {  
X      case STATE_READ: 
X       if (info->chan[info->curchan].status == STATUS_INUSE)
X	{ 
X         if (inb (iobase+STATUS) & EOC) /* check that conversion finished */
X	  printf (DEVFORMAT ": incomplete conversion\n", unit,
X	 	   'a'+EMUX(info->curchan), IMUX(info->curchan));	    
X	 else /* conversion is finished (should always be) */
X	  {   
X	   fifoent = (inb (iobase+ADHIGH) << 8) +
X	               inb (iobase+ADLOW);
X           if (putfifo(&(info->chan[info->curchan]), fifoent))
X    	    {
X	       printf (DEVFORMAT ": fifo overflow\n", unit,
X	 	        'a'+EMUX(info->curchan), IMUX(info->curchan));	    
X	    }
X
X	   selwakeup (&(info->chan[info->curchan].readselect)); 
X	  }
X	 }
X       /* goto setup state for next channel on list */
X       if ((info->curchan = info->chan[info->curchan].nextchan) < 0)
X	info->curchan = info->firstchan;  
X       /* notice lack of break here this implys a STATE_SETUP */ 
X      case STATE_SETUP: /* set the muxes and let them settle */
X#if NUMCHANNELS > NUMIMUXES    /* only do this if using external muxes */       
X       outb (iobase+STATUS, 
X	      EMUXMAKE(info->curchan) | IMUX(info->curchan) | IEN);
X       info->state = STATE_CONVERT;
X       break;
X#endif
X      case STATE_CONVERT: 
X       outb (iobase+STATUS, 
X	      EMUXMAKE(info->curchan) | IMUX(info->curchan) | IEN);
X       outb (iobase+ADHIGH, 0); /* start the conversion */
X       info->state = STATE_READ;
X       break;
X    }
X  else outb (iobase+STATUS, IEN); /* no list keep getting interrupts though */
X  
X  outb (iobase+CNTRCNTRL, LD2MODE4); /* counter 2 to mode 4 strobe */
X  outb (iobase+CNTR2, info->perlo); /* low part of the period count */
X  outb (iobase+CNTR2, info->perhi); /* high part of the period count */
X}
X
X   
X/* this will retrieve the next entry from the channels fifo 
X * returns 0 on success -1 on failure */
Xstatic int __inline getfifo (taiox_chan *pchan, u_short *fifoent)
X{   
X     if (pchan->fifostart == pchan->fifoend) return -1;
X     *fifoent = pchan->fifo[pchan->fifostart]; /* get an entry */
X     pchan->fifostart++; /* one less in fifo */
X     if (pchan->fifostart == FIFOSIZE) pchan->fifostart = 0; /* wrap around */
X     return 0;
X}
X
X   
X/* this will put an entry in fifo, returns 1 if the first item in 
X * fifo was wiped (overflow) or 0 if everything went fine */
Xstatic int __inline putfifo (taiox_chan *pchan, u_short fifoent)
X{   
X   pchan->fifo[pchan->fifoend] = fifoent; /* insert the entry in */
X   pchan->fifoend++; /* one more in fifo */
X   if (pchan->fifoend == FIFOSIZE) pchan->fifoend = 0; /* wrap around */ 
X   if (pchan->fifostart == pchan->fifoend) /* overflow */
X    {
X       pchan->fifostart++;
X       if (pchan->fifostart == FIFOSIZE) pchan->fifostart = 0;
X       return 1; /* we overflowed */
X    }
X   return 0; /* went in just fine */ 
X}
X   
X
X/* Driver initialization */
Xstatic void aiox_drvinit (void *unused)
X{
X  dev_t dev;  /* Type for holding device major/minor numbers (int) */
X
X  if (!aiox_devsw_installed)
X   {
X     dev = makedev (CDEV_MAJOR, 0);  /* description of device major */
X     cdevsw_add (&dev, &aiox_cdevsw, NULL);  /* put driver in cdev table */
X     aiox_devsw_installed=1;
X   }
X}
X
X/* System initialization call instance */
X
XSYSINIT (aioxdev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR,
X         aiox_drvinit,NULL);
X
X#endif
END-of-aiox.c
echo x - aioxioctl.h
sed 's/^X//' >aioxioctl.h << 'END-of-aioxioctl.h'
X/*
X * Copyright (c) 1997 Jamil J. Weatherbee
X * All rights reserved.
X *
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer
X *    in this position and unchanged.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. The name of the author may not be used to endorse or promote products
X *    derived from this software without specific prior written permission
X * 
X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
X * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
X * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
X * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
X * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
X * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
X * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
X * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X *
X * Industrial Computer Source model AIO8-P
X * 128 channel MUX capability via daisy chained AT-16P units
X * aioxioctl.h, definitions for aiox ioctl(), last revised November 10 1997
X * See http://www.indcompsrc.com/products/data/html/aio8g-p.html
X *     http://www.indcompsrc.com/products/data/html/at16-p.html
X *
X * Written by: Jamil J. Weatherbee <jamil@trojanhorse.ml.org>
X *
X */
X
X#ifndef _SYS_AIOXIOCTL_H_
X#define _SYS_AIOXIOCTL_H_
X
X#ifndef KERNEL
X#include <sys/types.h>
X#endif
X#include <sys/ioccom.h>
X
X/* Note: By default A/D conversions are started when a channel is open */
X
X/* Halt clocked A/D conversion on an open channel */
X#define AD_STOP _IO('D', 100) 
X/* Restart clocked A/D conversion on an open channel */
X#define AD_START _IO('D', 101)
X
X#endif
END-of-aioxioctl.h
exit

>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199711152006.MAA07024>