Re: Help implementing counter

Frank Mori Hess wrote:

>I've got a couple quibbles before I commit your code.  First, I'd like to 
>keep the configuration instructions 'flat'.  That is, just make two 
>seperate configuration instructions instead of making subcommands for a 
>single instruction.
>
Ok. I used:

  0 ID: INSN_CONFIG_8254_SET_MODE (0x1001)
  1 8254 Mode
    I8254_MODE0, I8254_MODE1, ..., I8254_MODE5
    OR'ed with:
    I8254_BCD, I8254_BINARY
   
  0 ID: INSN_CONFIG_8254_READ_STATUS (0x1002)
  1 <-- Status byte returned here.
    B7=Output
    B6=NULL Count
    B5-B0 Current mode.

>  Second, your actual write to the control register 
>should happen during the write instruction, and INSN_CONFIG_8254_SET_MODE 
>should only store into memory the mode that will be used in subsequent 
>writes.
>  
>
I donīt think thatīs a good idea. To read/write the counters you donīt 
need to set the mode.
Iīm storing the mode in the structure just for future uses, not because 
the actual code really needs it.
This is supposed to be used internally to avoid reading the registers, 
but actually is just memorized, not used. It also simplifies the 
initialization process for boards that uses one or more of the counters 
for internal purposes.

SET

-- 
Salvador Eduardo Tropea (SET). (Electronics Engineer)
Visit my home page: http://welcome.to/SetSoft or
http://www.geocities.com/SiliconValley/Vista/6552/
Alternative e-mail: set_at_computer.org set_at_ieee.org 
Address: Curapaligue 2124, Caseros, 3 de Febrero
Buenos Aires, (1678), ARGENTINA Phone: +(5411) 4759 0013
Index: comedi/drivers/das08.c
===================================================================
RCS file: /var/cvs/comedi/comedi/drivers/das08.c,v
retrieving revision 1.47
diff -u -r1.47 das08.c
--- comedi/drivers/das08.c	4 Jul 2003 20:00:26 -0000	1.47
+++ comedi/drivers/das08.c	3 Feb 2004 15:02:59 -0000
_at__at_ -5,6 +5,7 _at__at_
     COMEDI - Linux Control and Measurement Device Interface
     Copyright (C) 2000 David A. Schleef <ds_at_schleef.org>
     Copyright (C) 2001,2002,2003 Frank Mori Hess <fmhess_at_users.sourceforge.net>
+    Copyright (C) 2004 Salvador E. Tropea <set_at_users.sf.net> <set_at_ieee.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
_at__at_ -57,6 +58,7 _at__at_
 #include <linux/delay.h>
 #include <linux/pci.h>
 
+#include "comedi_counter_unstable.h"
 #include "8255.h"
 #include "das08.h"
 
_at__at_ -667,6 +669,135 _at__at_
 	return n;
 }
 
+
+static unsigned int i8254_read_channel_low(unsigned int base, int chan)
+{
+	unsigned int msb, lsb;
+
+        /* The following instructions must be in order.
+           We must avoid other process reading the counter's value in the
+           middle.
+           The spin_lock isn't needed since ioctl calls grab the big kernel 
+           lock automatically */
+        /*spin_lock(sp);*/
+        outb(chan<<6,base+I8254_CTRL);
+        base+=chan;
+	lsb=inb(base);
+	msb=inb(base);
+        /*spin_unlock(sp);*/
+
+	return lsb | (msb<<8);
+}
+
+static void i8254_write_channel_low(unsigned int base, int chan, unsigned int value)
+{
+	unsigned int msb, lsb;
+
+	lsb=value & 0xFF;
+	msb=value>>8;
+
+	/* write lsb, then msb */
+        base+=chan;
+        /* See comments in i8254_read_channel_low */
+        /*spin_lock(sp);*/
+	outb(lsb,base);
+	outb(msb,base);
+        /*spin_unlock(sp);*/
+}
+
+static unsigned int i8254_read_channel(struct i8254_struct *st, int channel)
+{
+        int chan=st->logic2phys[channel];
+
+        return i8254_read_channel_low(st->iobase,chan);
+}
+
+static void i8254_write_channel(struct i8254_struct *st, int channel, unsigned int value)
+{
+        int chan=st->logic2phys[channel];
+
+        i8254_write_channel_low(st->iobase,chan,value);
+}
+
+#define I8254_CH0_LM  0x30
+#define I8254_CH1_LM  0x60
+#define I8254_CH2_LM  0x80
+
+static void i8254_initialize(struct i8254_struct *st)
+{
+        unsigned int port=st->iobase+I8254_CTRL;
+        outb(I8254_CH0_LM | st->mode[0],port);
+        outb(I8254_CH1_LM | st->mode[1],port);
+        outb(I8254_CH2_LM | st->mode[2],port);
+}
+
+
+static void i8254_set_mode_low(unsigned int base, int channel, unsigned int mode)
+{
+        outb((channel<<6) | 0x30 | (mode & 0x0F),base+I8254_CTRL);
+}
+
+static void i8254_set_mode(struct i8254_struct *st, int channel, unsigned int mode)
+{
+        int chan=st->logic2phys[channel];
+
+        st->mode[chan]=mode;
+        return i8254_set_mode_low(st->iobase,chan,mode);
+}
+
+static unsigned int i8254_read_status_low(unsigned int base, int channel)
+{
+        outb(0xE0 | (2<<channel),base+I8254_CTRL);
+        return inb(base+channel);
+}
+
+static unsigned int i8254_read_status(struct i8254_struct *st, int channel)
+{
+        int chan=st->logic2phys[channel];
+        
+        return i8254_read_status_low(st->iobase,chan);
+}
+
+static int das08_counter_read(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data)
+{
+        int chan=insn->chanspec;
+
+        //printk("Reading counter channel %d ",chan);
+        data[0]=i8254_read_channel(&devpriv->i8254,chan);
+        //printk("=> 0x%08X\n",data[0]);
+           
+	return 1;
+}
+
+static int das08_counter_write(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data)
+{
+        int chan=insn->chanspec;
+
+        //printk("Writing counter channel %d with 0x%04X\n",chan,data[0]);
+        i8254_write_channel(&devpriv->i8254,chan,data[0]);
+           
+	return 1;
+}
+
+static int das08_counter_config(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
+{
+        int chan=insn->chanspec;
+
+	if(insn->n != 2)return -EINVAL;
+
+        switch (data[0]){
+                case INSN_CONFIG_8254_SET_MODE:
+                        i8254_set_mode(&devpriv->i8254,chan,data[1]);
+                        break;
+                case INSN_CONFIG_8254_READ_STATUS:
+                        data[1]=i8254_read_status(&devpriv->i8254,chan);
+                        break;
+                default:
+                        return -EINVAL;
+        }
+        return 1;
+}
+
 static int das08_attach(comedi_device *dev,comedi_devconfig *it);
 
 static comedi_driver driver_das08={
_at__at_ -698,7 +829,7 _at__at_
 
 	dev->board_name = thisboard->name;
 
-	if((ret=alloc_subdevices(dev, 5))<0)
+	if((ret=alloc_subdevices(dev, 6))<0)
 		return ret;
 
 	s=dev->subdevices+0;
_at__at_ -762,6 +893,30 _at__at_
 	if(thisboard->i8255_offset!=0){
 		subdev_8255_init(dev,s,NULL,(unsigned long)(dev->iobase+
 			thisboard->i8255_offset));
+	}else{
+		s->type=COMEDI_SUBD_UNUSED;
+	}
+
+	s=dev->subdevices+5;
+	/* 8254 */
+	if(thisboard->i8254_offset!=0){
+		s->type = COMEDI_SUBD_COUNTER;
+		s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+		s->n_chan = 3;
+		s->maxdata = 0xFFFF;
+		s->insn_read = das08_counter_read;
+		s->insn_write = das08_counter_write;
+		s->insn_config = das08_counter_config;
+                /* Set-up the 8254 structure */
+                devpriv->i8254.channels=3;
+                devpriv->i8254.logic2phys[0]=0;
+                devpriv->i8254.logic2phys[1]=1;
+                devpriv->i8254.logic2phys[2]=2;
+                devpriv->i8254.iobase=iobase+thisboard->i8254_offset;
+                devpriv->i8254.mode[0]=
+                devpriv->i8254.mode[1]=
+                devpriv->i8254.mode[2]=I8254_MODE0 | I8254_BINARY;
+                i8254_initialize(&devpriv->i8254);
 	}else{
 		s->type=COMEDI_SUBD_UNUSED;
 	}
Index: comedi/drivers/das08.h
===================================================================
RCS file: /var/cvs/comedi/comedi/drivers/das08.h,v
retrieving revision 1.2
diff -u -r1.2 das08.h
--- comedi/drivers/das08.h	21 Nov 2003 02:27:34 -0000	1.2
+++ comedi/drivers/das08.h	3 Feb 2004 15:03:15 -0000
_at__at_ -47,12 +47,26 _at__at_
 	unsigned int	iosize;	// number of ioports used
 } das08_board;
 
+struct i8254_struct
+{
+ int channels;        // available channels. Some could be used internally.
+ int logic2phys[3];   // to know which physical channel is.
+ int mode[3];         // the index is the real counter.
+ unsigned int iobase;
+};
+
+#define I8254_CNT0 0
+#define I8254_CNT1 1
+#define I8254_CNT2 2
+#define I8254_CTRL 3
+
 struct das08_private_struct{
 	unsigned int	do_mux_bits;	// bits for do/mux register on boards without seperate do register
 	unsigned int	do_bits;	// bits for do register on boards with register dedicated to digital out only
 	unsigned int	*pg_gainlist;
 	struct pci_dev *pdev;	// struct for pci-das08
 	unsigned int	pci_iobase;	// additional base address for pci-das08
+        struct i8254_struct i8254;
 };
 
 #define NUM_DAS08_CS_BOARDS 2
Index: comedi/drivers/comedi_counter_unstable.h
===================================================================
RCS file: /var/cvs/comedi/comedi/drivers/comedi_counter_unstable.h,v
retrieving revision 1.2
diff -u -r1.2 comedi_counter_unstable.h
--- comedi/drivers/comedi_counter_unstable.h	23 Nov 2003 19:12:26 -0000	1.2
+++ comedi/drivers/comedi_counter_unstable.h	3 Feb 2004 15:03:28 -0000
_at__at_ -103,3 +103,34 _at__at_
 	COMEDI_DEC_ACCUMULATOR,
 	COMEDI_RESET_ACCUMULATOR,
 };
+
+/*
+  8254 specific configuration.
+
+  It supports one config command with two subcommands:
+  
+  0 ID: INSN_CONFIG_8254_SET_MODE
+  1 8254 Mode
+    I8254_MODE0, I8254_MODE1, ..., I8254_MODE5
+    OR'ed with:
+    I8254_BCD, I8254_BINARY
+    
+  0 ID: INSN_CONFIG_8254_READ_STATUS
+  1 <-- Status byte returned here.
+    B7=Output
+    B6=NULL Count
+    B5-B0 Current mode.
+  
+*/
+#define INSN_CONFIG_8254_SET_MODE    0x1001
+#define INSN_CONFIG_8254_READ_STATUS 0x1002
+
+#define I8254_MODE0 (0<<1)  /* Interrupt on terminal count */
+#define I8254_MODE1 (1<<1)  /* Hardware retriggerable one-shot */
+#define I8254_MODE2 (2<<1)  /* Rate generator */
+#define I8254_MODE3 (3<<1)  /* Square wave mode */
+#define I8254_MODE4 (4<<1)  /* Software triggered strobe */
+#define I8254_MODE5 (5<<1)  /* Hardware triggered strobe (retriggerable) */
+#define I8254_BCD    1
+#define I8254_BINARY 0
+

Received on 2004-02-03Z15:10:42