![]() |
RTXI 1.3
|
00001 /* 00002 comedi/drivers/pcmad.c 00003 Hardware driver for Winsystems PCM-A/D12 and PCM-A/D16 00004 00005 COMEDI - Linux Control and Measurement Device Interface 00006 Copyright (C) 2000,2001 David A. Schleef <ds@schleef.org> 00007 00008 This program is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 2 of the License, or 00011 (at your option) any later version. 00012 00013 This program is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program; if not, write to the Free Software 00020 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00021 00022 */ 00023 /* 00024 Driver: pcmad 00025 Description: Winsystems PCM-A/D12, PCM-A/D16 00026 Author: ds 00027 Devices: [Winsystems] PCM-A/D12 (pcmad12), PCM-A/D16 (pcmad16) 00028 Status: untested 00029 00030 This driver was written on a bet that I couldn't write a driver 00031 in less than 2 hours. I won the bet, but never got paid. =( 00032 00033 Configuration options: 00034 [0] - I/O port base 00035 [1] - unused 00036 [2] - Analog input reference 00037 0 = single ended 00038 1 = differential 00039 [3] - Analog input encoding (must match jumpers) 00040 0 = straight binary 00041 1 = two's complement 00042 */ 00043 00044 #include <linux/comedidev.h> 00045 00046 #include <linux/ioport.h> 00047 00048 #define PCMAD_SIZE 4 00049 00050 #define PCMAD_STATUS 0 00051 #define PCMAD_LSB 1 00052 #define PCMAD_MSB 2 00053 #define PCMAD_CONVERT 1 00054 00055 struct pcmad_board_struct { 00056 const char *name; 00057 int n_ai_bits; 00058 }; 00059 static const struct pcmad_board_struct pcmad_boards[] = { 00060 { 00061 name: "pcmad12", 00062 n_ai_bits:12, 00063 }, 00064 { 00065 name: "pcmad16", 00066 n_ai_bits:16, 00067 }, 00068 }; 00069 00070 #define this_board ((const struct pcmad_board_struct *)(dev->board_ptr)) 00071 #define n_pcmad_boards (sizeof(pcmad_boards)/sizeof(pcmad_boards[0])) 00072 00073 struct pcmad_priv_struct { 00074 int differential; 00075 int twos_comp; 00076 }; 00077 #define devpriv ((struct pcmad_priv_struct *)dev->private) 00078 00079 static int pcmad_attach(comedi_device * dev, comedi_devconfig * it); 00080 static int pcmad_detach(comedi_device * dev); 00081 static comedi_driver driver_pcmad = { 00082 driver_name:"pcmad", 00083 module:THIS_MODULE, 00084 attach:pcmad_attach, 00085 detach:pcmad_detach, 00086 board_name:&pcmad_boards[0].name, 00087 num_names:n_pcmad_boards, 00088 offset:sizeof(pcmad_boards[0]), 00089 }; 00090 00091 COMEDI_INITCLEANUP(driver_pcmad); 00092 00093 #define TIMEOUT 100 00094 00095 static int pcmad_ai_insn_read(comedi_device * dev, comedi_subdevice * s, 00096 comedi_insn * insn, lsampl_t * data) 00097 { 00098 int i; 00099 int chan; 00100 int n; 00101 00102 chan = CR_CHAN(insn->chanspec); 00103 00104 for (n = 0; n < insn->n; n++) { 00105 outb(chan, dev->iobase + PCMAD_CONVERT); 00106 00107 for (i = 0; i < TIMEOUT; i++) { 00108 if ((inb(dev->iobase + PCMAD_STATUS) & 0x3) == 0x3) 00109 break; 00110 } 00111 data[n] = inb(dev->iobase + PCMAD_LSB); 00112 data[n] |= (inb(dev->iobase + PCMAD_MSB) << 8); 00113 00114 if (devpriv->twos_comp) { 00115 data[n] ^= (1 << (this_board->n_ai_bits - 1)); 00116 } 00117 } 00118 00119 return n; 00120 } 00121 00122 /* 00123 * options: 00124 * 0 i/o base 00125 * 1 unused 00126 * 2 0=single ended 1=differential 00127 * 3 0=straight binary 1=two's comp 00128 */ 00129 static int pcmad_attach(comedi_device * dev, comedi_devconfig * it) 00130 { 00131 int ret; 00132 comedi_subdevice *s; 00133 unsigned long iobase; 00134 00135 iobase = it->options[0]; 00136 printk("comedi%d: pcmad: 0x%04lx ", dev->minor, iobase); 00137 if (!request_region(iobase, PCMAD_SIZE, "pcmad")) { 00138 printk("I/O port conflict\n"); 00139 return -EIO; 00140 } 00141 dev->iobase = iobase; 00142 00143 if ((ret = alloc_subdevices(dev, 1)) < 0) 00144 return ret; 00145 if ((ret = alloc_private(dev, sizeof(struct pcmad_priv_struct))) < 0) 00146 return ret; 00147 00148 dev->board_name = this_board->name; 00149 00150 s = dev->subdevices + 0; 00151 s->type = COMEDI_SUBD_AI; 00152 s->subdev_flags = SDF_READABLE | AREF_GROUND; 00153 s->n_chan = 16; /* XXX */ 00154 s->len_chanlist = 1; 00155 s->insn_read = pcmad_ai_insn_read; 00156 s->maxdata = (1 << this_board->n_ai_bits) - 1; 00157 s->range_table = &range_unknown; 00158 00159 return 0; 00160 } 00161 00162 static int pcmad_detach(comedi_device * dev) 00163 { 00164 printk("comedi%d: pcmad: remove\n", dev->minor); 00165 00166 if (dev->irq) { 00167 free_irq(dev->irq, dev); 00168 } 00169 if (dev->iobase) 00170 release_region(dev->iobase, PCMAD_SIZE); 00171 00172 return 0; 00173 }