added ni_mio_cs.c
authorDavid Schleef <ds@schleef.org>
Fri, 5 May 2000 19:22:41 +0000 (19:22 +0000)
committerDavid Schleef <ds@schleef.org>
Fri, 5 May 2000 19:22:41 +0000 (19:22 +0000)
comedi/drivers/ni_mio_cs.c [new file with mode: 0644]

diff --git a/comedi/drivers/ni_mio_cs.c b/comedi/drivers/ni_mio_cs.c
new file mode 100644 (file)
index 0000000..c17e906
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+    module/atmio-E.c
+    Hardware driver for NI PCMCIA MIO E series cards
+
+    COMEDI - Linux Control and Measurement Device Interface
+    Copyright (C) 1997-2000 David A. Schleef <ds@stm.lbl.gov>
+
+    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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/*
+       The real guts of the driver is in ni-E.c, which is included
+       both here and in pcimio-E.c
+
+       
+       Interrupt support added by Truxton Fulton <trux@truxton.com>
+
+       References for specifications:
+       
+          321747b.pdf  Register Level Programmer Manual (obsolete)
+          321747c.pdf  Register Level Programmer Manual (new)
+          DAQ-STC reference manual
+
+       Other possibly relevant info:
+       
+          320517c.pdf  User manual (obsolete)
+          320517f.pdf  User manual (new)
+          320889a.pdf  delete
+          320906c.pdf  maximum signal ratings
+          321066a.pdf  about 16x
+          321791a.pdf  discontinuation of at-mio-16e-10 rev. c
+          321808a.pdf  about at-mio-16e-10 rev P
+          321837a.pdf  discontinuation of at-mio-16de-10 rev d
+          321838a.pdf  about at-mio-16de-10 rev N
+       
+       ISSUES:
+
+       need to deal with external reference for DAC, and other DAC
+       properties in board properties
+       
+       deal with at-mio-16de-10 revision D to N changes, etc.
+       
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <linux/malloc.h>
+#ifdef CONFIG_COMEDI_RT
+#include <linux/rtl.h>
+#endif
+#include <comedi_module.h>
+#include <ni_stc.h>
+#include <8255.h>
+
+#undef Status
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#undef DEBUG
+
+#define ATMIO 1
+#undef PCIMIO
+
+/*
+ *  AT specific setup
+ */
+
+#define NI_SIZE 0x20
+
+static struct caldac_struct *type1[]={&caldac_mb88341,NULL,NULL};
+static struct caldac_struct *type2[]={&caldac_dac8800,&caldac_dac8043,NULL};
+
+static ni_board ni_boards[]={
+       {       device_id:      44,
+               name:           "xe-50",
+               n_adchan:       16,
+               adbits:         16,
+               ai_fifo_depth:  8192,
+               alwaysdither:   0,
+               gainlkup:       ai_gain_16,
+               ai_speed:       800,
+               n_aochan:       2,
+               aobits:         12,
+               ao_fifo_depth:  2048,
+               ao_unipolar:    1,
+               has_8255:       0,
+               caldac:         type1,
+       },
+};
+
+
+static int ni_irqpin[]={-1,-1,-1,0,1,2,-1,3,-1,-1,4,5,6,-1,-1,7};
+
+#define interrupt_pin(a)       (ni_irqpin[(a)])
+
+#define IRQ_POLARITY 0
+
+
+/* How we access registers */
+
+#define ni_writew(a,b)         (outw((a),(b)+dev->iobase))
+#define ni_readw(a)            (inw((a)+dev->iobase))
+#define ni_writeb(a,b)         (outb((a),(b)+dev->iobase))
+#define ni_readb(a)            (inb((a)+dev->iobase))
+#define ni_writeb_p(a,b)       (outb_p((a),(b)+dev->iobase))
+#define ni_readb_p(a)          (inb_p((a)+dev->iobase))
+
+
+/*
+ * this is how we access windowed registers
+ */
+
+#define win_out(a,b) (ni_writew((b),Window_Address),ni_writew((a),Window_Data))
+#define win_in(b) (ni_writew((b),Window_Address),ni_readw(Window_Data))
+#define win_save() (ni_readw(Window_Address))
+#define win_restore(a) (ni_writew((a),Window_Address))
+
+
+typedef struct{
+       int dio;
+       int ao0p,ao1p;
+       int lastchan;
+       int last_do;
+       int rt_irq;
+       int irqmask;
+       int aimode;
+
+       unsigned short ao_mode1;
+       unsigned short ao_mode2;
+       unsigned short ao_mode3;
+       unsigned short ao_cmd1;
+       unsigned short ao_cmd2;
+       unsigned short ao_cmd3;
+       unsigned short ao_trigger_select;
+}ni_private;
+#define devpriv ((ni_private *)dev->private)
+
+static int mio_cs_attach(comedi_device *dev,comedi_devconfig *it);
+static int mio_cs_detach(comedi_device *dev);
+comedi_driver driver_atmio={
+       driver_name:    "mio-cs",
+       module:         &__this_module,
+       attach:         mio_cs_attach,
+       detach:         mio_cs_detach,
+};
+
+
+#include "ni_mio_common.c"
+
+
+static int init_stage2(comedi_device *dev,comedi_devconfig *it);
+static int ni_getboardtype(comedi_device *dev);
+
+/* clean up allocated resources */
+int atmio_E_free(comedi_device *dev)
+{
+       if(dev->iobase)
+               release_region(dev->iobase,NI_SIZE);
+       if(dev->irq){
+               comedi_free_irq(dev->irq,dev);
+       }
+
+       return 0;
+}
+
+/* called when driver is removed */
+static int mio_cs_detach(comedi_device *dev)
+{
+       return atmio_E_free(dev);
+}
+
+void mio_cs_config(dev_link_t *link);
+static void cs_release(u_long arg);
+static void cs_detach(dev_link_t *);
+static int irq_mask;
+
+static dev_link_t *dev_list = NULL;
+static dev_info_t dev_info = "ni_mio_cs";
+static int mio_cs_event(event_t event, int priority, event_callback_args_t *args);
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+       error_info_t err = { func, ret };
+       CardServices(ReportError, handle, &err);
+}
+
+static dev_link_t *cs_attach(void)
+{
+       dev_link_t *link;
+       client_reg_t client_reg;
+       int ret;
+
+       link=kmalloc(sizeof(*link),GFP_KERNEL);
+       if(!link)return NULL;
+       memset(link,0,sizeof(*link));
+
+       link->release.function = &cs_release;
+       link->release.data = (u_long)link;
+       
+       link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+       link->io.NumPorts1 = 16;
+       link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+       link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+       link->irq.IRQInfo2 = irq_mask;
+       link->conf.Attributes = CONF_ENABLE_IRQ;
+       link->conf.Vcc = 50;
+       link->conf.IntType = INT_MEMORY_AND_IO;
+       
+       link->next = dev_list;
+       dev_list = link;
+
+       client_reg.dev_info = &dev_info;
+       client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+       client_reg.EventMask =
+               CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+               CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+               CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+       client_reg.event_handler = &mio_cs_event;
+       client_reg.Version = 0x0210;
+       client_reg.event_callback_args.client_data = link;
+       ret = CardServices(RegisterClient, &link->handle, &client_reg);
+       if (ret != CS_SUCCESS) {
+               cs_error(link->handle, RegisterClient, ret);
+               cs_detach(link);
+               return NULL;
+       }
+
+       return link;
+}
+
+static void cs_release(u_long arg)
+{
+       dev_link_t *link=(void *)arg;
+
+       CardServices(ReleaseConfiguration, link->handle);
+       CardServices(ReleaseIO, link->handle, &link->io);
+       CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+       link->state &= ~DEV_CONFIG;
+}
+
+static void cs_detach(dev_link_t *link)
+{
+       // delete linkp
+       
+       
+
+}
+
+static int mio_cs_event(event_t event, int priority, event_callback_args_t *args)
+{
+       dev_link_t *link = args->client_data;
+
+
+       switch(event){
+       case CS_EVENT_CARD_REMOVAL:
+               link->state &= ~DEV_PRESENT;
+               if(link->state & DEV_CONFIG) {
+                       link->release.expires = jiffies+HZ/20;
+                       link->state |= DEV_RELEASE_PENDING;
+                       add_timer(&link->release);
+               }
+               break;
+       case CS_EVENT_CARD_INSERTION:
+               link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+               mio_cs_config(link);
+               break;
+       case CS_EVENT_PM_SUSPEND:
+               link->state |= DEV_SUSPEND;
+               /* fall through */
+       case CS_EVENT_RESET_PHYSICAL:
+               if(link->state & DEV_CONFIG)
+                       CardServices(ReleaseConfiguration, link->handle);
+               break;
+       case CS_EVENT_PM_RESUME:
+               link->state &= ~DEV_SUSPEND;
+               /* fall through */
+       case CS_EVENT_CARD_RESET:
+               if(DEV_OK(link))
+                       CardServices(RequestConfiguration, link->handle, &link->conf);
+               break;
+       }
+       return 0;
+}
+
+static int mio_cs_attach(comedi_device *dev,comedi_devconfig *it)
+{
+       if(!strcmp("ni_E",it->board_name)){
+               printk("comedi: 'ni_E' deprecated.  Use 'atmio-E'\n");
+       }else if(!strcmp("atmio-E",it->board_name)){
+               ;
+       }else{
+               return 0;
+       }
+
+       return init_stage2(dev,it);
+}
+
+
+void mio_cs_config(dev_link_t *link)
+{
+       client_handle_t handle = link->handle;
+       tuple_t tuple;
+       u_short buf[128];
+       cisparse_t parse;
+       int ret;
+
+       tuple.TupleData = (cisdata_t *)buf;
+       tuple.TupleOffset = 0;
+       tuple.TupleDataMax = 255;
+       tuple.Attributes = 0;
+       tuple.DesiredTuple = CISTPL_CONFIG;
+
+       ret=CardServices(GetFirstTuple, handle,&tuple);
+       link->conf.ConfigBase = parse.config.base;
+       link->conf.Present = parse.config.rmask[0];
+
+       link->state |= DEV_CONFIG;
+
+#if 0
+       tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
+       tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
+       info->multi (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
+#endif
+
+#if 0
+       tuple.DesiredTuple = CISTPL_MANFID;
+       if(first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
+               info->manfid = le16_to_cpu(buf[0]);
+               // search
+       }
+#endif
+
+       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+       CardServices(GetTupleData, handle, &tuple);
+       CardServices(ParseTuple, handle, &tuple, &parse);
+       CardServices(RequestIO, handle, &link->io);
+       
+       CardServices(RequestIRQ, handle, &link->irq);
+       CardServices(RequestConfiguration, handle, &link->conf);
+
+       printk("irq = %d\n",link->irq.AssignedIRQ);
+       printk("iobase = 0x%04x\n",link->io.BasePort1);
+       //printk("mfr = 0x%04x\n",link->io.BasePort1);
+       
+}
+
+static int init_stage2(comedi_device *dev,comedi_devconfig *it)
+{
+       int             ret;
+       int             iobase;
+       int             board;
+       int             irq;
+
+       
+       /* reserve our I/O region */
+
+       iobase=0x200;
+       if(it->options[0])iobase=it->options[0];
+       
+       printk("comedi%d: ni_E: 0x%04x",dev->minor,iobase);
+       if(check_region(iobase,NI_SIZE)<0){
+               printk(" I/O port conflict\n");
+               return -EIO;
+       }
+       request_region(iobase,NI_SIZE,"ni_E");
+
+       dev->iobase=iobase;
+       dev->iosize=NI_SIZE;
+       
+       
+       /* board existence sanity check */
+       
+#ifdef DEBUG
+       {
+               int i;
+
+               printk(" board fingerprint:");
+              for(i=0;i<16;i+=2){
+                       printk(" %04x %02x",inw(dev->iobase+i),inb(dev->iobase+i+1));
+               }
+       }
+#endif
+       
+       /* get board type */
+
+       board=ni_getboardtype(dev);
+       if(board<0)return -EIO;
+       
+       printk(" %s",ni_boards[board].name);
+       dev->board_name=ni_boards[board].name;
+
+       /* irq stuff */
+
+       irq=it->options[1];
+       if(irq!=0){
+               if(irq<0 || irq>15 || ni_irqpin[irq]==-1){
+                       printk(" invalid irq\n");
+                       return -EINVAL;
+               }
+               printk(" ( irq = %d )",irq);
+               if( (ret=comedi_request_irq(irq,ni_E_interrupt,NI_E_IRQ_FLAGS,"atmio-E",dev))<0 ){
+                       printk(" irq not available\n");
+                       return -EINVAL;
+               }
+               dev->irq=irq;
+       }
+       
+       /* allocate private area */
+       
+       if((ret=alloc_private(dev,sizeof(ni_private)))<0)
+               return ret;
+       
+       dev->board=board;
+
+       /* generic E series stuff in ni-E.c */
+
+       if( (ret=ni_E_init(dev,it))<0 ){
+               return ret;
+       }
+       
+       return 0;
+}
+
+
+static int ni_getboardtype(comedi_device *dev)
+{
+       int device_id=ni_read_eeprom(dev,511);
+       int i;
+       
+       for(i=0;i<n_ni_boards;i++){
+               if(ni_boards[i].device_id==device_id){
+                       return i;
+               }
+       }
+       if(device_id==255){
+               printk(" can't find board\n");
+       }else if(device_id == 0){
+               printk(" EEPROM read error (?) or device not found\n");
+       }else{
+               printk(" unknown device ID %d -- contact author\n",device_id);
+       }
+       return -1;
+}
+
+
+#ifdef MODULE
+int init_module(void)
+{
+       servinfo_t serv;
+
+       comedi_driver_register(&driver_atmio);
+       CardServices(GetCardServicesInfo, &serv);
+       if(serv.Revision != CS_RELEASE_CODE){
+               printk(KERN_NOTICE "mio_cs: Card Services release "
+                       "does not match!\n");
+               return -1;
+       }
+       register_pccard_driver(&dev_info, &cs_attach, &cs_detach);
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       unregister_pccard_driver(&dev_info);
+       while(dev_list != NULL)
+               cs_detach(dev_list);
+       comedi_driver_unregister(&driver_atmio);
+}
+#endif