Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 6 Nov 1997 23:40:02 -0800 (PST)
From:      "0000-Administrator (J. Weatherbee)" <jamil@trojanhorse.ml.org>
To:        freebsd-bugs
Subject:   Re: i386/4816: FreeBSD driver for Industrial Computer Source DIO48S/AT-P
Message-ID:  <199711070740.XAA16421@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR i386/4816; it has been noted by GNATS.

From: "0000-Administrator (J. Weatherbee)" <jamil@trojanhorse.ml.org>
To: freebsd-gnats-submit@freebsd.org, jamil@trojanhorse.ml.org
Cc:  Subject: Re: i386/4816: FreeBSD driver for Industrial Computer Source DIO48S/AT-P
Date: Thu, 06 Nov 1997 23:34:26 -0800

 This is a multi-part message in MIME format.
 
 --------------446B9B3D2781E494167EB0E7
 Content-Type: text/plain; charset=us-ascii
 Content-Transfer-Encoding: 7bit
 
 This is the complete driver package with a working probe routine
 utilizing a special feature of this particular board. Man page is also
 updated.  It is now safe to have it configured in your kernel even
 without one of these boards because of the probe.   In fact I have the
 same kernel with this compiled in on all of my diskless workstations (3)
 even though even 1 actually has one and it has worked very nicely this
 way.
 
 Things to do: Implement the fabled 6800 virtual machine in the driver,
 but for this century we will leave that alone.
 
 Actually I was thinking of designing an isa card with multiple 68hc11's
 that could be programmed through a driver interface. Complete with
 digital and analog interfaces.
 
 --------------446B9B3D2781E494167EB0E7
 Content-Type: application/x-shar; name="dio.shar"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline; filename="dio.shar"
 
 # 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:
 #
 #	dio/Makefile
 #	dio/dio.4
 #	dio/dio.c
 #	dio/dioctl.h
 #
 echo x - dio/Makefile
 sed 's/^X//' >dio/Makefile << 'END-of-dio/Makefile'
 X# Make file to install the dio driver files in their proper places
 X
 Xinstall:
 X	install -c -o root -g wheel -m 0644 dio.c /sys/i386/isa
 X	install -c -o root -g bin -m 644 dioctl.h /sys/sys
 X	install -c -o bin -g bin -m 444 dioctl.h /usr/include/sys
 X	install -c -o bin -g bin -m 444 dio.4 /usr/share/man/man4/dio.4
 X	gzip -f /usr/share/man/man4/dio.4
 X	install -c -o bin -g bin -m 444 dio.4 /usr/share/man/man4/i386/dio.4
 X	gzip -f /usr/share/man/man4/i386/dio.4
 X        
 END-of-dio/Makefile
 echo x - dio/dio.4
 sed 's/^X//' >dio/dio.4 << 'END-of-dio/dio.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 DIO48S/AT-P
 X.\" 48 channel digital input/output board with change of state interrupt
 X.\" dio.c, character device driver, last revised November 06 1997
 X.\" See http://www.indcompsrc.com/products/data/html/dio48s_at-p.html
 X.\"
 X.\" Written by: Jamil J. Weatherbee <jamil@trojanhorse.ml.org>
 X.\"
 X.\"
 X.Dd November 6, 1997
 X.Dt DIO 4 i386
 X.Os FreeBSD
 X.Sh NAME
 X.Nm dio
 X.Nd
 XIndustrial Computer Source DIO48S/AT-P driver
 X.Sh SYNOPSIS
 X.Cd "device dio0 at isa? port 0x250 tty irq 12 vector diointr"
 X.Sh DESCRIPTION
 XThis driver supports the Industrial Computer Source \fIDIO48S/AT-P 48 Line
 XDigital I/O board with Change of State Interrupt\fP.
 X.Pp
 XThis board provides 6 8 bit digital I/O ports.  It makes use of two type
 X8255-5 Programmable Peripheral Interface chips.  Each port can be
 Xindependently configured as input or output.  Ports configured as input can
 Xindividually have their change of state interrupts enabled.
 X.Pp
 XThe selection of input or output mode for each port is via flags passed
 Xthrough the
 X.Xr open 2
 Xcall:
 X.Pp
 X.Bd -literal -offset indent
 XO_RDONLY	open for input
 XO_WRONLY	open for output
 XO_RDWR		open for output
 X.Ed
 X.Pp
 XSelection of the I/O port is through the minor number:
 X.Pp
 X.Bd -literal -offset indent
 XThe 8 bit minor number format is UUUUUCCC, where
 XUUUUU: board unit (X=0-31)
 X  CCC: digital i/o channel (0-2,4-6)
 X.Pp
 Xch  name       devnode  conn  signal pins (lsb/msb)
 X0   PA port 0  dioXa    J2    47, 45, 43, 41, 39, 37, 35, 33
 X1   PB port 0  dioXb    J2    31, 29, 27, 25, 23, 21, 19, 17
 X2   PC port 0  dioXc    J2    15, 13, 11,  9,  7,  5,  3,  1
 X4   PA port 1  dioXd    J3    47, 45, 43, 41, 39, 37, 35, 33
 X5   PB port 1  dioXe    J3    31, 29, 27, 25, 23, 21, 19, 17
 X6   PC port 1  dioXf    J3    15, 13, 11,  9,  7,  5,  3,  1
 X.Ed
 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 file
 X.Pa <sys/dioctl.h>.
 X.Bl -tag -width DIOENBCHS
 X.It Dv DIOENBCHS
 XSet an input to Change of State enabled mode.  Calls to
 X.Xr read 2
 Xwill never block; however,
 X.Xr select 2
 Xcan be used to wait for inputs to change that have had their interrupts
 Xenabled in this fashion.
 X.It Dv DIODISCHS
 XUndo the effect of a previous DIOENBCHS reqest.
 X.Sh BUGS
 XThe TST/BEN jumper must be set to TST for this driver to operate correctly.
 XPlease note that in TST position (tristate buffers software enabled) this
 Xparticular board has a "feature" which causes all output ports
 Xto momentarily (a few microseconds) go to tristate condition whenever
 Xanother port on the same 8255-5 is opened or closed.
 XAlso, only MODE 0 is supported by the \fIDIO48S/AT-P\fP.
 X.Sh SEE ALSO
 Xhttp://www.indcompsrc.com/products/data/html/dio48s_at-p.html
 X.Sh AUTHOR
 XJamil J. Weatherbee <jamil@trojanhorse.ml.org>.
 END-of-dio/dio.4
 echo x - dio/dio.c
 sed 's/^X//' >dio/dio.c << 'END-of-dio/dio.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 DIO48S/AT-P
 X * 48 channel digital input/output board with change of state interrupt
 X * dio.c, character device driver, last revised November 06 1997
 X * See http://www.indcompsrc.com/products/data/html/dio48s_at-p.html
 X *
 X * Written by: Jamil J. Weatherbee <jamil@trojanhorse.ml.org>
 X *
 X */
 X
 X
 X/* Include Files */
 X
 X#include "dio.h"
 X#if NDIO > 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/dioctl.h> 
 X
 X#ifdef DEVFS
 X#include <sys/devfsext.h>
 X#endif 
 X
 X/* Local Defines */
 X
 X#define CDEV_MAJOR 84
 X#define NUMPORTS 16
 X
 X#define PORTA 0x0
 X#define PORTB 0x1
 X#define PORTC 0x2
 X#define CNTRL0 0x3
 X#define PORTD 0x4
 X#define PORTE 0x5
 X#define PORTF 0x6
 X#define CNTRL1 0x7
 X#define ENBCHS 0xB
 X#define CLRCHS 0xF
 X
 X/* mode bits for the control registers */
 X
 X#define MODE0 0x80 
 X#define AINMASK 0x10
 X#define BINMASK 0x02
 X#define CINMASK 0x09
 X#define CHSMASK 0xff
 X
 X/* Minor allocations:
 X * UUUUUCCC
 X * UUUUU: board unit (X=0-31) 
 X * CCC: digital i/o channel (0-2,4-6) 
 X *      channel  name       devnode  connector  signal pins (lsb/msb)
 X *      0        PA port 0  dioXa    J2         47, 45, 43, 41, 39, 37, 35, 33
 X *      1        PB port 0  dioXb    J2         31, 29, 27, 25, 23, 21, 19, 17
 X *      2        PC port 0  dioXc    J2         15, 13, 11,  9,  7,  5,  3,  1
 X *      4        PA port 1  dioXd    J3         47, 45, 43, 41, 39, 37, 35, 33
 X *      5        PB port 1  dioXe    J3         31, 29, 27, 25, 23, 21, 19, 17
 X *      6        PC port 1  dioXf    J3         15, 13, 11,  9,  7,  5,  3,  1
 X */
 X
 X#define MAXUNITS 32
 X#define NUMCHANNELS 8 
 X#define CFGSIZE 6
 X#define UNIT(dev) ((minor(dev) & 0xf8) >> 3)
 X#define CHANNEL(dev) (minor(dev) & 0x07)
 X#define LMINOR(unit, channel) ((unit << 3) + channel)
 X
 X/* Port status setting */
 X
 X#define STATUS_UNUSED 0
 X#define STATUS_POLLED_INPUT 1
 X#define STATUS_CHS_INPUT 2
 X#define STATUS_OUTPUT 3
 X#define STATUS_CONTROLLER 4 
 X
 X/* Type definitions */
 Xtypedef struct 
 X{ 
 X  struct isa_device *isaunit; /* ptr to isa device information */     
 X  u_char laststate[NUMCHANNELS]; /* The last state of the device */
 X  u_char chs; /* last setting posted to chs */
 X  short status[NUMCHANNELS]; /* The status for the port, see above */ 
 X  struct selinfo readselect[NUMCHANNELS]; /* chs select info for each chan */
 X  short ready[NUMCHANNELS]; /* set to true if chs input is ready */ 
 X  void *devfs_token[NUMCHANNELS]; /* devfs token for each channels node */
 X   
 X} tdio_unit;
 X
 X
 X/* general info on how to configure a unit based on its channel statuses */
 Xtypedef struct {
 X                 int channel; /* the channel in question 0-2,4-6 */
 X                 int controller; /* the controller to mask CNTRL0 or CNTRL1 */
 X                 int input_mask; /* the mask on channel as input */
 X                 int chs_mask; /* how to mask off chs */ 
 X                 char *nodename; /* the name of the device node (DEVFS) */
 X               } tdio_cfg;
 X
 X
 X/* Function Prototypes */
 X
 Xstatic int dio_probe (struct isa_device *idp);  /* Check for dio board */
 Xstatic int dio_attach (struct isa_device *idp);  /* Take dio board */
 Xstatic int dio_ioctl (dev_t dev, int cmd, caddr_t data, 
 X			 int fflag, struct proc *p); /* Special ops */
 Xstatic int dio_open (dev_t dev, int oflags, int devtype, struct proc *p);
 Xstatic void dio_sync (int unit); /* updates the control registers */
 Xstatic int dio_close (dev_t dev, int fflag, int devtype, struct proc *p);
 Xstatic void dio_strategy (struct buf *bp); /* called by rawread and rawwrite */
 Xstatic int dio_select (dev_t dev, int which, struct proc *p); 
 X
 X/* Global Data */
 X
 Xstatic int dio_devsw_installed = 0;  /* Protect against reinit multiunit */
 Xstatic tdio_unit *dio_unit[NDIO]; /* data structs for each unit */ 
 Xstatic tdio_cfg dio_cfg[CFGSIZE] = { { PORTA, CNTRL0, AINMASK, 0x01,"dio%da"},
 X                                     { PORTB, CNTRL0, BINMASK, 0x02,"dio%db"},
 X                                     { PORTC, CNTRL0, CINMASK, 0x04,"dio%dc"},
 X                                     { PORTD, CNTRL1, AINMASK, 0x08,"dio%dd"},
 X                                     { PORTE, CNTRL1, BINMASK, 0x10,"dio%de"},
 X                                     { PORTF, CNTRL1, CINMASK, 0x20,"dio%df"}};
 X
 X/* Character device switching structure */
 Xstatic struct cdevsw dio_cdevsw = { dio_open, dio_close, rawread, rawwrite,
 X                                    dio_ioctl, nostop, noreset, nodevtotty,
 X                                    dio_select, nommap, dio_strategy, "dio",
 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 diodriver = { dio_probe, dio_attach, "dio", 0 };
 X
 X
 X/* Unit input chs interrupt handling routine
 X * BTW: the standard DIO48s board has a 2.5 microsecond response time
 X *      to a change of state (theoretically) */
 Xvoid diointr (int unit)
 X{
 X  tdio_unit *info = dio_unit[unit];
 X  int iobase = info->isaunit->id_iobase;
 X  int channel; 
 X  u_char curstate; 
 X   
 X  for (channel=0; channel<NUMCHANNELS; channel++)
 X   if ((info->status[channel] == STATUS_CHS_INPUT) &&
 X       ((curstate = inb (iobase+channel)) != info->laststate[channel]))
 X    {	
 X      info->laststate[channel] = curstate; /* save cur state as last state */
 X      info->ready[channel] = 1; /* now ready for chs based read */
 X      selwakeup (&info->readselect[channel]); /* wakeup any selectors */
 X    }
 X  outb (iobase+CLRCHS, 0); /* Clear CHS interrupt latch */
 X}
 X
 X
 X/* Since this device can always be read/write the select() allows the user
 X * to actually make some use of the change of state interrupts by calling
 X * select() on a read descriptor that has had chs interrupts enabled via
 X * ioctl (fd, DIOENBCHS, NULL) */
 Xstatic int dio_select (dev_t dev, int which, struct proc *p)
 X{
 X  int unit = UNIT(dev); /* Get unit number */
 X  int channel = CHANNEL(dev); /* and channel in that unit */
 X  tdio_unit *info = dio_unit[unit]; /* info on this unit */
 X  int s; /* interrupt priority */
 X   
 X  s = spltty(); /* prevent diointr() from occuring here */
 X  
 X  switch (which) /* are we sleeping on a read or write descriptor */ 
 X   {
 X     case FWRITE: splx(s); return 1; /* always ready for writing */
 X     case FREAD: if (info->status[channel] == STATUS_CHS_INPUT)
 X	          {
 X		    if (info->ready[channel]) /* if ready */
 X		     {
 X		       splx(s);
 X		       return 1;		  
 X		     }
 X		     
 X		    /* record the select request */ 
 X		    selrecord (p, &info->readselect[channel]);
 X		    splx(s); 
 X		    return 0; /* not ready but will get waken up when ready */
 X		  }
 X                 splx(s); return 1; /* any input except chs set is ready */
 X   }
 X  
 X  splx(s); 
 X  return 0; 
 X}
 X
 X
 X/* The probing routine - returns number of bytes needed */
 Xstatic int dio_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 port; 
 X  int ncfg; 
 X   
 X  if ((unit < 0) || (unit >= NDIO) || (unit >= MAXUNITS))
 X   { 
 X     printf ("dio: invalid unit number (%d)\n", unit);
 X     return 0;
 X   }
 X   
 X  /* the unit number is ok, lets check if used */
 X  if (dio_unit[unit]) 
 X   {
 X     printf ("dio: unit (%d) already attached\n", unit);
 X     return 0;
 X   }
 X
 X  outb (iobase+CNTRL0, MODE0); /* both ports to output (still tristated) */
 X  outb (iobase+CNTRL1, MODE0);
 X   
 X  /* output to each port on the card and chech your outputs */
 X  for (ncfg=0; ncfg < CFGSIZE; ncfg++)
 X   {  
 X     /* 8255 always switches outputs to low after mode switch */ 
 X     if (inb(iobase+dio_cfg[ncfg].channel) != 0x00) return 0;    
 X     outb (iobase+dio_cfg[ncfg].channel, ncfg);
 X     if (inb(iobase+dio_cfg[ncfg].channel) != ncfg) return 0;
 X   }
 X   
 X  return NUMPORTS; /* this device needs this many ports */ 
 X}
 X
 X
 X/* The attachment routine - returns true on success */
 Xstatic int dio_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  tdio_unit *info; /* pointer to driver specific info for unit */
 X  int ncfg; /* configuration record number */
 X   
 X  if (!(info = malloc(sizeof(*info), M_DEVBUF, M_NOWAIT)))
 X   {
 X     printf ("dio%d: cannot allocate driver storage\n", unit);
 X     return 0;
 X   }
 X  dio_unit[unit] = info; /* make sure to save the pointer! (prev bug) */
 X  bzero (info, sizeof(*info)); /* clear info structure to all false */
 X  info->isaunit = idp;  /* store ptr to isa device information */
 X
 X  outb (iobase+CLRCHS, 0); /* Clear CHS interrupt latch */
 X   
 X  /* only need to set this once */
 X  info->status[CNTRL0] = info->status[CNTRL1] = STATUS_CONTROLLER;
 X      
 X  dio_sync (unit); /* This will have the effect of setting all to
 X		    * polled inputs */
 X  
 X  /* insert devfs nodes */
 X  
 X#ifdef DEVFS   
 X  for (ncfg=0; ncfg<CFGSIZE; ncfg++)
 X   info->devfs_token[dio_cfg[ncfg].channel] = 
 X     devfs_add_devswf(&dio_cdevsw, LMINOR(unit, dio_cfg[ncfg].channel), DV_CHR,
 X		      UID_ROOT, GID_WHEEL, 0600 ,dio_cfg[ncfg].nodename, unit);
 X#endif   
 X   
 X  printf ("dio%d: Interrupt-driven unit\n", unit);
 X  return 1; /* obviously successful */
 X}
 X
 X
 X/* I/O control routine */
 Xstatic int dio_ioctl (dev_t dev, int cmd, caddr_t data, 
 X			 int fflag, struct proc *p)
 X{
 X  int unit = UNIT(dev); /* Get unit number */
 X  int channel = CHANNEL(dev); /* and channel in that unit */
 X  tdio_unit *info = dio_unit[unit]; /* info on this unit */
 X  int iobase = info->isaunit->id_iobase; /* the iobase of unit in question */
 X  short status = info->status[channel]; /* the status of unit in question */
 X  int s; /* interrupt priority level */ 
 X   
 X  switch (cmd)
 X   {  
 X    case DIOENBCHS: if ((status == STATUS_POLLED_INPUT) ||
 X			 (status == STATUS_CHS_INPUT))
 X	             {
 X		       s = spltty();
 X                       info->status[channel] = STATUS_CHS_INPUT;
 X		       info->ready[channel] = 0;
 X		       dio_sync (unit);
 X                       /* this should prevent any chs simply by ioctling */
 X		       info->laststate[channel] = inb (iobase+channel);
 X                       splx (s);
 X		       return 0;
 X	             }
 X                    return EPERM;
 X      
 X    case DIODISCHS: if ((status == STATUS_POLLED_INPUT) ||
 X			 (status == STATUS_CHS_INPUT))
 X	             {
 X		       s = spltty();	
 X                       info->status[channel] = STATUS_POLLED_INPUT;
 X                       dio_sync (unit);
 X                       splx(s);
 X		       return 0;
 X		     }
 X                    return EPERM; 
 X   }
 X  return ENOTTY; /* inappropriate (unhandled) ioctl for device */  
 X}
 X
 X
 X/* How to open a channel (a channel can only be opened by one process) */
 Xstatic int dio_open (dev_t dev, int oflags, int devtype, struct proc *p)
 X{
 X  int unit = UNIT(dev); /* Get unit number */
 X  int channel = CHANNEL(dev); /* and channel in that unit */
 X  tdio_unit *info;  /* info on this unit */
 X  int iobase; /* the iobase of unit in question */
 X  short status; /* the status of unit in question */
 X  int s; /* priority value */
 X   
 X  /* We know the major is safe, now check the minor */
 X 
 X  if ((unit >= NDIO) || (unit >= MAXUNITS)) return ENXIO; /* unit ok? */
 X  if (channel >= NUMCHANNELS) return ENXIO; /* is the channel no valid? */ 
 X  if (!dio_unit[unit]) return ENXIO; /* is the unit attached? */
 X   
 X  /* standard assigns now safe */
 X  info = dio_unit[unit]; 
 X  iobase = info->isaunit->id_iobase; 
 X   
 X  if (info->status[channel]) return EBUSY; /* channel is already opened 
 X					    * or maybye is a controller */
 X   
 X  /* If it can be written to, it must be an output port */ 
 X  if (oflags & FWRITE)   
 X   {
 X     s = spltty(); 
 X     info->status[channel] = STATUS_OUTPUT;
 X     dio_sync (unit);
 X     splx(s); 
 X     return 0;
 X   } 
 X  if (oflags & FREAD)
 X   {
 X     s = spltty(); 
 X     info->status[channel] = STATUS_POLLED_INPUT;
 X     dio_sync (unit); 
 X     info->laststate[channel] = inb (iobase+channel); /* get cur state */    
 X     splx(s);
 X     return 0;
 X   }
 X  return EPERM; /* Needs to be either read or write or both */  	
 X}
 X
 X
 X/* Closing a channel is really easy just change its status to
 X * inputs (actually STATUS_UNUSED) and resync */
 Xstatic int dio_close (dev_t dev, int fflag, int devtype, struct proc *p)
 X{
 X  int unit = UNIT(dev); /* Get unit number */
 X  int channel = CHANNEL(dev); /* and channel in that unit */
 X  tdio_unit *info = dio_unit[unit]; /* info on this unit */
 X  int s; /* priority value */
 X   
 X  s = spltty();
 X  info->status[channel] = STATUS_UNUSED; /* this channel now closed */
 X  dio_sync (unit); /* channel switched to input (looks high to me) */
 X  splx(s); 
 X   
 X  return 0; /* close is always successful */ 
 X}
 X
 X
 X/* called by kernel routines rawread and rawrite to actually perform the
 X * i/o via inb() and outb() */
 Xstatic void dio_strategy (struct buf *bp)
 X{
 X  /* this is the machine i/o port that we are going to r/w */
 X  int unit = UNIT(bp->b_dev);
 X  int channel = CHANNEL(bp->b_dev);
 X  tdio_unit *info = dio_unit[unit];
 X  int port = info->isaunit->id_iobase+channel;
 X  u_char *c = (u_char *) bp->b_un.b_addr; /* current byte were ioing */
 X  int bufsz = bp->b_bcount; /* size of the buffer to r/w */
 X  int index; /* current index in the buffer (byte number were on) */
 X  int s; 
 X   
 X  if (bp->b_flags & B_READ) /* read into the buffer */
 X   { 
 X     s = spltty(); 
 X     info->ready[channel] = 0; /* now we are not ready */ 
 X     splx(s);
 X     for (index=0; index<bufsz; index++) *c++ = inb (port);
 X   }
 X  else /* write out from the buffer */
 X   for (index=0; index<bufsz; index++, c++) outb (port, *c);
 X 
 X  bp->b_resid = 0; /* no i/o remaining to be done (we hope) */ 
 X  biodone (bp); /* done with the buffer */ 
 X   
 X}
 X
 X
 X/* Syncronize the control registers of the unit with the values in the 
 X * status info table for the unit */
 Xstatic void dio_sync (int unit)
 X{
 X  tdio_unit* info = dio_unit[unit]; 
 X  int iobase = info->isaunit->id_iobase; 
 X  int ncfg; /* current configuration counter */
 X   
 X  info->laststate[CNTRL0] = info->laststate[CNTRL1] = 0x00; /* init. masks */ 
 X  info->chs = CHSMASK; /* all chs interrupts masked case */ 
 X   
 X  for (ncfg=0; ncfg<CFGSIZE; ncfg++)
 X   {   
 X     switch (info->status[dio_cfg[ncfg].channel])
 X      {
 X       case STATUS_OUTPUT: info->laststate[dio_cfg[ncfg].controller] &= 
 X	                     ~dio_cfg[ncfg].input_mask; break; /* is output */
 X       case STATUS_CHS_INPUT: info->chs &= ~dio_cfg[ncfg].chs_mask; /* chs */
 X       default: info->laststate[dio_cfg[ncfg].controller] |=
 X	          dio_cfg[ncfg].input_mask; /* is input */   
 X      }
 X   }
 X  
 X  /* now we need to actually write these things to the registers */
 X   
 X  outb (iobase+ENBCHS, info->chs); /* write the chs intrerrupt mask */
 X  outb (iobase+CNTRL0, info->laststate[CNTRL0] | MODE0); /* cntrl0 8255 */
 X  outb (iobase+CNTRL0, info->laststate[CNTRL0]); /* cntrl0 buffer */
 X  outb (iobase+CNTRL1, info->laststate[CNTRL1] | MODE0); /* cntrl1 8255 */
 X  outb (iobase+CNTRL1, info->laststate[CNTRL1]); /* cntrl1 buffer */
 X
 X}
 X
 X
 X
 X/* Driver initialization */
 Xstatic void dio_drvinit (void *unused)
 X{
 X  dev_t dev;  /* Type for holding device major/minor numbers (int) */
 X
 X  if (!dio_devsw_installed)
 X   {
 X     dev = makedev (CDEV_MAJOR, 0);  /* description of device major */
 X     cdevsw_add (&dev, &dio_cdevsw, NULL);  /* put driver in cdev table */
 X     dio_devsw_installed=1;
 X   }
 X}
 X
 X
 X/* System initialization call instance */
 X
 XSYSINIT (diodev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR,
 X         dio_drvinit,NULL);
 X
 X#endif
 X
 END-of-dio/dio.c
 echo x - dio/dioctl.h
 sed 's/^X//' >dio/dioctl.h << 'END-of-dio/dioctl.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 DIO48S/AT-P
 X * 48 channel digital input/output board with change of state interrupt
 X * dioctl.h, definitions for dio ioctl(), last revised November 06 1997
 X * See http://www.indcompsrc.com/products/data/html/dio48s_at-p.html
 X *
 X * Written by: Jamil J. Weatherbee <jamil@trojanhorse.ml.org>
 X *
 X */
 X
 X#ifndef _SYS_DIOCTL_H_
 X#define _SYS_DIOCTL_H_
 X
 X#ifndef KERNEL
 X#include <sys/types.h>
 X#endif
 X#include <sys/ioccom.h>
 X
 X/* Change of state related ioctls. CHS is disabled by default, this makes it
 X * a polling channel. With CHS enabled the channel is state driven. */
 X
 X/* enable change of state interrupt on a read only port */
 X#define DIOENBCHS _IO('D',1) 
 X/* disable change of state interrupt on a read only port */
 X#define DIODISCHS _IO('D',2)
 X
 X#endif
 END-of-dio/dioctl.h
 exit
 
 
 --------------446B9B3D2781E494167EB0E7--
 



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