📄 cb_das16_cs.c
字号:
/* comedi/drivers/das16cs.c Skeleton code for a Comedi driver COMEDI - Linux Control and Measurement Device Interface Copyright (C) 2000, 2001, 2002 David A. Schleef <ds@schleef.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 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.*//*Driver: cb_das16_cs.oDescription: Computer Boards PC-CARD DAS16/16Devices: (ComputerBoards) PC-CARD DAS16/16 [cb_das16_cs], PC-CARD DAS16/16-AOAuthor: dsUpdated: Mon, 04 Nov 2002 20:04:21 -0800Status: experimental*/#include <linux/comedidev.h>#include <linux/delay.h>#include <linux/pci.h>#include <pcmcia/version.h>#include <pcmcia/cs_types.h>#include <pcmcia/cs.h>#include <pcmcia/cistpl.h>#include <pcmcia/ds.h>#include "8253.h"#define DAS16CS_SIZE 18#define DAS16CS_ADC_DATA 0#define DAS16CS_DIO_MUX 2#define DAS16CS_MISC1 4#define DAS16CS_MISC2 6#define DAS16CS_CTR0 8#define DAS16CS_CTR1 10#define DAS16CS_CTR2 12#define DAS16CS_CTR_CONTROL 14#define DAS16CS_DIO 16typedef struct das16cs_board_struct{ char *name; int device_id; int n_ao_chans;}das16cs_board;static das16cs_board das16cs_boards[] = { { device_id: 0x0000, /* unknown */ name: "PC-CARD DAS16/16", n_ao_chans: 0, }, { device_id: 0x0039, name: "PC-CARD DAS16/16-AO", n_ao_chans: 2, },};#define n_boards (sizeof(das16cs_boards)/sizeof(das16cs_boards[0]))#define thisboard ((das16cs_board *)dev->board_ptr)typedef struct{ dev_link_t *link; lsampl_t ao_readback[2]; unsigned short status1; unsigned short status2;}das16cs_private;#define devpriv ((das16cs_private *)dev->private)static int das16cs_attach(comedi_device *dev,comedi_devconfig *it);static int das16cs_detach(comedi_device *dev);static comedi_driver driver_das16cs={ driver_name: "cb_das16_cs", module: THIS_MODULE, attach: das16cs_attach, detach: das16cs_detach,};static dev_link_t *dev_list = NULL;static comedi_lrange das16cs_ai_range = { 4, { RANGE( -10, 10 ), RANGE( -5, 5 ), RANGE( -2.5, 2.5 ), RANGE( -1.25, 1.25 ),}};static void das16cs_interrupt(int irq, void *d, struct pt_regs *regs);static int das16cs_ai_rinsn(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int das16cs_ai_cmd(comedi_device *dev,comedi_subdevice *s);static int das16cs_ai_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd);static int das16cs_ao_winsn(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int das16cs_ao_rinsn(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int das16cs_dio_insn_bits(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int das16cs_dio_insn_config(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int das16cs_timer_insn_read(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int das16cs_timer_insn_config(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int get_prodid(comedi_device *dev, dev_link_t *link){ client_handle_t handle = link->handle; tuple_t tuple; u_short buf[128]; int prodid = 0; tuple.TupleData = (cisdata_t *) buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.DesiredTuple = CISTPL_MANFID; tuple.Attributes = TUPLE_RETURN_COMMON; if((CardServices(GetFirstTuple,handle, &tuple) == CS_SUCCESS) && (CardServices(GetTupleData,handle,&tuple) == CS_SUCCESS)){ prodid = le16_to_cpu(buf[1]); } return prodid;}static das16cs_board *das16cs_probe(comedi_device *dev, dev_link_t *link){ int id; int i; id = get_prodid(dev,link); for(i=0;i<n_boards;i++){ if(das16cs_boards[i].device_id==id){ return das16cs_boards + i; } } printk("unknown board!\n"); return NULL;}static int das16cs_attach(comedi_device *dev,comedi_devconfig *it){ dev_link_t *link; comedi_subdevice *s; int ret; int i; printk("comedi%d: cb_das16_cs: ",dev->minor); link = dev_list; /* XXX hack */ if(!link)return -EIO; dev->iobase = link->io.BasePort1; printk("I/O base=0x%04x ",dev->iobase); printk("fingerprint:\n"); for(i=0;i<48;i+=2){ printk("%04x ",inw(dev->iobase + i)); } printk("\n"); ret = comedi_request_irq(link->irq.AssignedIRQ, das16cs_interrupt, SA_SHIRQ, "cb_das16_cs", dev); if(ret<0){ return ret; } dev->irq = link->irq.AssignedIRQ; printk("irq=%d ",dev->irq); dev->board_ptr = das16cs_probe(dev, link); if(!dev->board_ptr)return -EIO; dev->board_name = thisboard->name; if(alloc_private(dev,sizeof(das16cs_private))<0) return -ENOMEM; if(alloc_subdevices(dev, 4)<0) return -ENOMEM; s=dev->subdevices+0; dev->read_subdev=s; /* analog input subdevice */ s->type=COMEDI_SUBD_AI; s->subdev_flags=SDF_READABLE|SDF_GROUND|SDF_DIFF; s->n_chan=16; s->maxdata=0xffff; s->range_table=&das16cs_ai_range; s->len_chanlist=16; s->insn_read = das16cs_ai_rinsn; s->do_cmd = das16cs_ai_cmd; s->do_cmdtest = das16cs_ai_cmdtest; s=dev->subdevices+1; /* analog output subdevice */ if(thisboard->n_ao_chans){ s->type=COMEDI_SUBD_AO; s->subdev_flags=SDF_WRITABLE; s->n_chan=thisboard->n_ao_chans; s->maxdata=0xffff; s->range_table = &range_bipolar10; s->insn_write = &das16cs_ao_winsn; s->insn_read = &das16cs_ao_rinsn; } s=dev->subdevices+2; /* digital i/o subdevice */ if(1){ s->type=COMEDI_SUBD_DIO; s->subdev_flags=SDF_READABLE|SDF_WRITABLE; s->n_chan=8; s->maxdata=1; s->range_table=&range_digital; s->insn_bits = das16cs_dio_insn_bits; s->insn_config = das16cs_dio_insn_config; }else{ s->type = COMEDI_SUBD_UNUSED; } s=dev->subdevices+3; /* timer subdevice */ if(0){ s->type=COMEDI_SUBD_TIMER; s->subdev_flags=SDF_READABLE|SDF_WRITABLE; s->n_chan=1; s->maxdata=0xff; s->range_table = &range_unknown; s->insn_read = das16cs_timer_insn_read; s->insn_config = das16cs_timer_insn_config; }else{ s->type = COMEDI_SUBD_UNUSED; } printk("attached\n"); return 1;}static int das16cs_detach(comedi_device *dev){ printk("comedi%d: das16cs: remove\n",dev->minor); if(dev->irq){ comedi_free_irq(dev->irq, dev); } return 0;}static void das16cs_interrupt(int irq, void *d, struct pt_regs *regs){ //comedi_device *dev = d;}/* * "instructions" read/write data in "one-shot" or "software-triggered" * mode. */static int das16cs_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){ int i; int to; int aref; int range; int chan; static int range_bits[] = { 0x800, 0x000, 0x100, 0x200 }; chan = CR_CHAN(insn->chanspec); aref = CR_AREF(insn->chanspec); range = CR_RANGE(insn->chanspec); outw(chan, dev->iobase + 2); devpriv->status1 &= ~0xf320; devpriv->status1 |= (aref==AREF_DIFF)?0:0x0020; outw(devpriv->status1, dev->iobase + 4); devpriv->status2 &= ~0xff00; devpriv->status2 |= range_bits[range]; outw(devpriv->status2, dev->iobase + 6); for(i=0;i<insn->n;i++){ outw(0, dev->iobase);#define TIMEOUT 1000 for(to=0;to<TIMEOUT;to++){ if(inw(dev->iobase + 4) & 0x0080)break; } if(to==TIMEOUT){ printk("cb_das16_cs: ai timeout\n"); return -ETIME; } data[i] = (unsigned short)inw(dev->iobase + 0); } return i;}static int das16cs_ai_cmd(comedi_device *dev,comedi_subdevice *s){ return -EINVAL;}static int das16cs_ai_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd){ int err=0; int tmp; /* cmdtest tests a particular command to see if it is valid. * Using the cmdtest ioctl, a user can create a valid cmd * and then have it executes by the cmd ioctl. * * cmdtest returns 1,2,3,4 or 0, depending on which tests * the command passes. */ /* step 1: make sure trigger sources are trivially valid */ tmp=cmd->start_src; cmd->start_src &= TRIG_NOW; if(!cmd->start_src || tmp!=cmd->start_src)err++; tmp=cmd->scan_begin_src; cmd->scan_begin_src &= TRIG_TIMER|TRIG_EXT; if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++; tmp=cmd->convert_src; cmd->convert_src &= TRIG_TIMER|TRIG_EXT; if(!cmd->convert_src || tmp!=cmd->convert_src)err++; tmp=cmd->scan_end_src; cmd->scan_end_src &= TRIG_COUNT; if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++; tmp=cmd->stop_src; cmd->stop_src &= TRIG_COUNT|TRIG_NONE; if(!cmd->stop_src || tmp!=cmd->stop_src)err++; if(err)return 1; /* step 2: make sure trigger sources are unique and mutually compatible */ /* note that mutual compatiblity is not an issue here */ if(cmd->scan_begin_src!=TRIG_TIMER && cmd->scan_begin_src!=TRIG_EXT)err++; if(cmd->convert_src!=TRIG_TIMER && cmd->convert_src!=TRIG_EXT)err++; if(cmd->stop_src!=TRIG_COUNT && cmd->stop_src!=TRIG_NONE)err++; if(err)return 2; /* step 3: make sure arguments are trivially compatible */ if(cmd->start_arg!=0){ cmd->start_arg=0; err++; }#define MAX_SPEED 10000 /* in nanoseconds */#define MIN_SPEED 1000000000 /* in nanoseconds */ if(cmd->scan_begin_src==TRIG_TIMER){ if(cmd->scan_begin_arg<MAX_SPEED){ cmd->scan_begin_arg=MAX_SPEED; err++; } if(cmd->scan_begin_arg>MIN_SPEED){ cmd->scan_begin_arg=MIN_SPEED; err++; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -