From 5ffaf08fa407919bc1cc414bac895ac7b329c315 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Wed, 30 Nov 2005 17:51:24 +0000 Subject: [PATCH] new driver --- comedi/drivers/Makefile.am | 1 + comedi/drivers/pcm3724.c | 310 +++++++++++++++++++++++++++++++++++++ 2 files changed, 311 insertions(+) create mode 100644 comedi/drivers/pcm3724.c diff --git a/comedi/drivers/Makefile.am b/comedi/drivers/Makefile.am index 5c1dd3ac..02f5dd20 100644 --- a/comedi/drivers/Makefile.am +++ b/comedi/drivers/Makefile.am @@ -138,6 +138,7 @@ module_PROGRAMS = \ ni_atmio16d.ko \ ni_at_a2150.ko \ ni_at_ao.ko \ + pcm3724.ko \ pcm3730.ko \ pcmad.ko \ poc.ko \ diff --git a/comedi/drivers/pcm3724.c b/comedi/drivers/pcm3724.c new file mode 100644 index 00000000..bb26a3eb --- /dev/null +++ b/comedi/drivers/pcm3724.c @@ -0,0 +1,310 @@ +/* + module/pcm724.c + + Drew Csillag + + hardware driver for Advantech card: + card: PCM-3724 + driver: pcm3724 + + Options for PCM-3724 + [0] - IO Base +*/ +/* +Driver: pcm3724.o +Description: Advantech PCM-3724 +Author: Drew Csillag +Devices: [Advantech] PCM-3724 (pcm724) +Status: tested + +This is driver for digital I/O boards PCM-3724 with 48 DIO. +It needs 8255.o for operations and only immediate mode is supported. +See the source for configuration details. + +Copy/pasted/hacked from pcm724.c +*/ +/* + * check_driver overrides: + * comedi_insn + */ + +#include + +#include +#include + +#include "8255.h" + +#define PCM3724_SIZE 16 +#define SIZE_8255 4 + +#define BUF_C0 0x1 +#define BUF_B0 0x2 +#define BUF_A0 0x4 +#define BUF_C1 0x8 +#define BUF_B1 0x10 +#define BUF_A1 0x20 + +#define GATE_A0 0x4 +#define GATE_B0 0x2 +#define GATE_C0 0x1 +#define GATE_A1 0x20 +#define GATE_B1 0x10 +#define GATE_C1 0x8 + +/* from 8255.c */ +#define CR_CW 0x80 +#define _8255_CR 3 +#define CR_B_IO 0x02 +#define CR_B_MODE 0x04 +#define CR_C_IO 0x09 +#define CR_A_IO 0x10 +#define CR_A_MODE(a) ((a)<<5) +#define CR_CW 0x80 + +static int pcm3724_attach(comedi_device *dev,comedi_devconfig *it); +static int pcm3724_detach(comedi_device *dev); + +typedef struct { + char *name; // driver name + int dio; // num of DIO + int numofports; // num of 8255 subdevices + unsigned int IRQbits; // allowed interrupts + int io_range; // len of IO space +} boardtype; + +//used to track configured dios +typedef struct { + int dio_1; + int dio_2; +} priv_pcm3724; +static boardtype boardtypes[] = +{ + {"pcm3724", 48, 2, 0x00fc, PCM3724_SIZE,}, +}; + +#define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype)) +#define this_board ((boardtype *)dev->board_ptr) + +static comedi_driver driver_pcm3724={ + driver_name: "pcm3724", + module: THIS_MODULE, + attach: pcm3724_attach, + detach: pcm3724_detach, + board_name: boardtypes, + num_names: n_boardtypes, + offset: sizeof(boardtype), +}; +COMEDI_INITCLEANUP(driver_pcm3724); + +// (setq c-basic-offset 8) + +static int subdev_8255_cb(int dir,int port,int data,unsigned long arg) +{ + int iobase=arg; + unsigned char inbres; + //printk("8255cb %d %d %d %x\n", dir,port,data,arg); + if(dir){ + //printk("8255 cb outb(%x, %x)\n", data, iobase+port); + outb(data,iobase+port); + return 0; + }else{ + inbres = inb(iobase+port); + //printk("8255 cb inb(%x) = %x\n", iobase+port, inbres); + return inbres; + } +} + +static int compute_buffer(int config, int devno, comedi_subdevice *s) +{ + /* 1 in io_bits indicates output */ + if(s->io_bits&0x0000ff) { + if (devno == 0) { + config |= BUF_A0; + } + else { + config |= BUF_A1; + } + } + if(s->io_bits&0x00ff00) { + if (devno == 0) { + config |= BUF_B0; + } + else { + config |= BUF_B1; + } + } + if(s->io_bits&0xff0000) { + if (devno == 0) { + config |= BUF_C0; + } + else { + config |= BUF_C1; + } + } + return config; +} + +static void do_3724_config(comedi_device *dev,comedi_subdevice *s, + int chanspec) +{ + int config; + int buffer_config; + int port_8255_cfg; + + config=CR_CW; + buffer_config = 0; + + /* 1 in io_bits indicates output, 1 in config indicates input */ + if(!(s->io_bits&0x0000ff)) { + config|=CR_A_IO; + } + if(!(s->io_bits&0x00ff00)) { + config|=CR_B_IO; + } + if(!(s->io_bits&0xff0000)) { + config|=CR_C_IO; + } + + buffer_config = compute_buffer(0, 0, dev->subdevices); + buffer_config = compute_buffer(buffer_config, 1, (dev->subdevices)+1); + + if (s == dev->subdevices) { + port_8255_cfg = dev->iobase + _8255_CR; + } + else { + port_8255_cfg = dev->iobase + SIZE_8255 + _8255_CR; + } + outb(buffer_config, dev->iobase + 8); /* update buffer register */ + //printk("pcm3724 buffer_config (%x) %d, %x\n", dev->iobase + _8255_CR, chanspec, buffer_config); + outb(config, port_8255_cfg); +} + +static void enable_chan(comedi_device *dev, comedi_subdevice *s, + int chanspec) +{ + unsigned int mask; + int gatecfg; + priv_pcm3724 *priv; + + gatecfg = 0; + priv = (priv_pcm3724*)(dev->private); + + mask = 1 << CR_CHAN(chanspec); + if (s == dev->subdevices){ // subdev 0 + priv->dio_1 |= mask; + } + else { //subdev 1 + priv->dio_2 |= mask; + } + if (priv->dio_1 & 0xff0000){ + gatecfg |= GATE_C0; + } + if (priv->dio_1 & 0xff00){ + gatecfg |= GATE_B0; + } + if (priv->dio_1 & 0xff){ + gatecfg |= GATE_A0; + } + if (priv->dio_2 & 0xff0000){ + gatecfg |= GATE_C1; + } + if (priv->dio_2 & 0xff00){ + gatecfg |= GATE_B1; + } + if (priv->dio_2 & 0xff){ + gatecfg |= GATE_A1; + } + // printk("gate control %x\n", gatecfg); + outb(gatecfg, dev->iobase + 9); +} + +/* overriding the 8255 insn config */ +static int subdev_3724_insn_config(comedi_device *dev, comedi_subdevice *s, + comedi_insn *insn, lsampl_t *data) +{ + unsigned int mask; + unsigned int bits; + + mask=1<chanspec); + if(mask&0x0000ff){ + bits=0x0000ff; + }else if(mask&0x00ff00){ + bits=0x00ff00; + }else if(mask&0x0f0000){ + bits=0x0f0000; + }else{ + bits=0xf00000; + } + + switch(data[0]){ + case INSN_CONFIG_DIO_INPUT: + s->io_bits&=~bits; + break; + case INSN_CONFIG_DIO_OUTPUT: + s->io_bits|=bits; + break; + case INSN_CONFIG_DIO_QUERY: + data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT; + return insn->n; + break; + default: + return -EINVAL; + } + + do_3724_config(dev,s, insn->chanspec); + enable_chan(dev, s, insn->chanspec); + return 1; +} + +static int pcm3724_attach(comedi_device *dev,comedi_devconfig *it) +{ + int iobase,iorange; + int ret,i,n_subdevices; + + iobase=it->options[0]; + iorange=this_board->io_range; + if((ret=alloc_private(dev,sizeof(priv_pcm3724)))<0) + return -ENOMEM; + + ((priv_pcm3724*)(dev->private))->dio_1 = 0; + ((priv_pcm3724*)(dev->private))->dio_2 = 0; + + printk("comedi%d: pcm3724: board=%s, 0x%03x ",dev->minor, + this_board->name,iobase); + if(check_region(iobase,iorange)<0){ + printk("I/O port conflict\n"); + return -EIO; + } + + request_region(iobase, iorange, "pcm3724"); + dev->iobase=iobase; + dev->board_name = this_board->name; + printk("\n"); + + n_subdevices=this_board->numofports; + + if((ret=alloc_subdevices(dev, n_subdevices))<0) + return ret; + + for(i=0;in_subdevices;i++){ + subdev_8255_init(dev, dev->subdevices+i, subdev_8255_cb, + (unsigned long)(dev->iobase+SIZE_8255*i)); + ((dev->subdevices)+i)->insn_config = subdev_3724_insn_config; + }; + return 0; +} + +static int pcm3724_detach(comedi_device *dev) +{ + int i; + + for(i=0;in_subdevices;i++){ + subdev_8255_cleanup(dev,dev->subdevices+i); + } + release_region(dev->iobase,this_board->io_range); + + return 0; +} + + -- 2.26.2