![]() |
RTXI 1.3
|
00001 /******************************************************************************* 00002 comedi/drivers/pci1723.c 00003 00004 COMEDI - Linux Control and Measurement Device Interface 00005 Copyright (C) 2000 David A. Schleef <ds@schleef.org> 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 2 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program; if not, write to the Free Software 00019 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00020 00021 *******************************************************************************/ 00022 /* 00023 Driver: adv_pci1723 00024 Description: Advantech PCI-1723 00025 Author: yonggang <rsmgnu@gmail.com>, Ian Abbott <abbotti@mev.co.uk> 00026 Devices: [Advantech] PCI-1723 (adv_pci1723) 00027 Updated: Mon, 14 Apr 2008 15:12:56 +0100 00028 Status: works 00029 00030 Configuration Options: 00031 [0] - PCI bus of device (optional) 00032 [1] - PCI slot of device (optional) 00033 00034 If bus/slot is not specified, the first supported 00035 PCI device found will be used. 00036 00037 Subdevice 0 is 8-channel AO, 16-bit, range +/- 10 V. 00038 00039 Subdevice 1 is 16-channel DIO. The channels are configurable as input or 00040 output in 2 groups (0 to 7, 8 to 15). Configuring any channel implicitly 00041 configures all channels in the same group. 00042 00043 TODO: 00044 00045 1. Add the two milliamp ranges to the AO subdevice (0 to 20 mA, 4 to 20 mA). 00046 2. Read the initial ranges and values of the AO subdevice at start-up instead 00047 of reinitializing them. 00048 3. Implement calibration. 00049 */ 00050 00051 #include <linux/comedidev.h> 00052 00053 #include "comedi_pci.h" 00054 00055 #define ADVANTECH_VENDOR 0x13fe /* Advantech PCI vendor ID */ 00056 00057 // hardware types of the cards 00058 #define TYPE_PCI1723 0 00059 00060 #define IORANGE_1723 0x2A 00061 00062 /* all the registers for the pci1723 board */ 00063 #define PCI1723_DA(N) ((N)<<1) /* W: D/A register N (0 to 7) */ 00064 00065 #define PCI1723_SYN_SET 0x12 /*synchronized set register */ 00066 #define PCI1723_ALL_CHNNELE_SYN_STROBE 0x12 /*synchronized status register */ 00067 00068 #define PCI1723_RANGE_CALIBRATION_MODE 0x14 /* range and calibration mode */ 00069 #define PCI1723_RANGE_CALIBRATION_STATUS 0x14 /* range and calibration status */ 00070 00071 #define PCI1723_CONTROL_CMD_CALIBRATION_FUN 0x16 /* SADC control command for calibration function */ 00072 #define PCI1723_STATUS_CMD_CALIBRATION_FUN 0x16 /* SADC control status for calibration function */ 00073 00074 #define PCI1723_CALIBRATION_PARA_STROBE 0x18 /* Calibration parameter strobe */ 00075 00076 #define PCI1723_DIGITAL_IO_PORT_SET 0x1A /* Digital I/O port setting */ 00077 #define PCI1723_DIGITAL_IO_PORT_MODE 0x1A /* Digital I/O port mode */ 00078 00079 #define PCI1723_WRITE_DIGITAL_OUTPUT_CMD 0x1C /* Write digital output command */ 00080 #define PCI1723_READ_DIGITAL_INPUT_DATA 0x1C /* Read digital input data */ 00081 00082 #define PCI1723_WRITE_CAL_CMD 0x1E /* Write calibration command */ 00083 #define PCI1723_READ_CAL_STATUS 0x1E /* Read calibration status */ 00084 00085 #define PCI1723_SYN_STROBE 0x20 /* Synchronized strobe */ 00086 00087 #define PCI1723_RESET_ALL_CHN_STROBE 0x22 /* Reset all D/A channels strobe */ 00088 00089 #define PCI1723_RESET_CAL_CONTROL_STROBE 0x24 /* Reset the calibration controller strobe */ 00090 00091 #define PCI1723_CHANGE_CHA_OUTPUT_TYPE_STROBE 0x26 /* Change D/A channels output type strobe */ 00092 00093 #define PCI1723_SELECT_CALIBRATION 0x28 /* Select the calibration Ref_V */ 00094 00095 //static unsigned short pci_list_builded=0; /*=1 list of card is know */ 00096 00097 static const comedi_lrange range_pci1723 = { 1, { 00098 BIP_RANGE(10) 00099 } 00100 }; 00101 00102 /* 00103 * Board descriptions for pci1723 boards. 00104 */ 00105 typedef struct pci1723_board_struct { 00106 const char *name; 00107 int vendor_id; // PCI vendor a device ID of card 00108 int device_id; 00109 int iorange; 00110 char cardtype; 00111 int n_aochan; // num of D/A chans 00112 int n_diochan; // num of DIO chans 00113 int ao_maxdata; // resolution of D/A 00114 const comedi_lrange *rangelist_ao; // rangelist for D/A 00115 } boardtype; 00116 00117 static const boardtype boardtypes[] = { 00118 { 00119 name: "pci1723", 00120 vendor_id:ADVANTECH_VENDOR, 00121 device_id:0x1723, 00122 iorange: IORANGE_1723, 00123 cardtype:TYPE_PCI1723, 00124 n_aochan:8, 00125 n_diochan:16, 00126 ao_maxdata:0xffff, 00127 rangelist_ao:&range_pci1723, 00128 }, 00129 }; 00130 00131 /* This is used by modprobe to translate PCI IDs to drivers. Should 00132 * only be used for PCI and ISA-PnP devices */ 00133 static DEFINE_PCI_DEVICE_TABLE(pci1723_pci_table) = { 00134 {PCI_VENDOR_ID_ADVANTECH, 0x1723, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 00135 {0} 00136 }; 00137 00138 MODULE_DEVICE_TABLE(pci, pci1723_pci_table); 00139 00140 /* 00141 * The comedi_driver structure tells the Comedi core module 00142 * which functions to call to configure/deconfigure (attach/detach) 00143 * the board, and also about the kernel module that contains 00144 * the device code. 00145 */ 00146 static int pci1723_attach(comedi_device * dev, comedi_devconfig * it); 00147 static int pci1723_detach(comedi_device * dev); 00148 00149 #define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype)) 00150 00151 static comedi_driver driver_pci1723 = { 00152 driver_name:"adv_pci1723", 00153 module:THIS_MODULE, 00154 attach:pci1723_attach, 00155 detach:pci1723_detach, 00156 }; 00157 00158 /* this structure is for data unique to this hardware driver. */ 00159 typedef struct { 00160 int valid; //card is usable; 00161 00162 struct pci_dev *pcidev; 00163 unsigned char da_range[8]; // D/A output range for each channel 00164 00165 sampl_t ao_data[8]; // data output buffer 00166 } pci1723_private; 00167 00168 /*the following macro to make it easy to 00169 * access the private structure. 00170 */ 00171 #define devpriv ((pci1723_private *)dev->private) 00172 00173 #define this_board boardtypes 00174 00175 /* 00176 * the pci1723 card reset; 00177 */ 00178 static int pci1723_reset(comedi_device * dev) 00179 { 00180 int i; 00181 DPRINTK("adv_pci1723 EDBG: BGN: pci1723_reset(...)\n"); 00182 00183 outw(0x01, dev->iobase + PCI1723_SYN_SET); // set synchronous output mode 00184 00185 for (i = 0; i < 8; i++) { 00186 // set all outputs to 0V 00187 devpriv->ao_data[i] = 0x8000; 00188 outw(devpriv->ao_data[i], dev->iobase + PCI1723_DA(i)); 00189 // set all ranges to +/- 10V 00190 devpriv->da_range[i] = 0; 00191 outw(((devpriv->da_range[i] << 4) | i), 00192 PCI1723_RANGE_CALIBRATION_MODE); 00193 } 00194 00195 outw(0, dev->iobase + PCI1723_CHANGE_CHA_OUTPUT_TYPE_STROBE); // update ranges 00196 outw(0, dev->iobase + PCI1723_SYN_STROBE); // update outputs 00197 00198 // set asynchronous output mode 00199 outw(0, dev->iobase + PCI1723_SYN_SET); 00200 00201 DPRINTK("adv_pci1723 EDBG: END: pci1723_reset(...)\n"); 00202 return 0; 00203 } 00204 00205 static int pci1723_insn_read_ao(comedi_device * dev, comedi_subdevice * s, 00206 comedi_insn * insn, lsampl_t * data) 00207 { 00208 int n, chan; 00209 00210 chan = CR_CHAN(insn->chanspec); 00211 DPRINTK(" adv_PCI1723 DEBUG: pci1723_insn_read_ao() ----- \n"); 00212 for (n = 0; n < insn->n; n++) 00213 data[n] = devpriv->ao_data[chan]; 00214 00215 return n; 00216 } 00217 00218 /* 00219 analog data output; 00220 */ 00221 static int pci1723_ao_write_winsn(comedi_device * dev, comedi_subdevice * s, 00222 comedi_insn * insn, lsampl_t * data) 00223 { 00224 int n, chan; 00225 chan = CR_CHAN(insn->chanspec); 00226 00227 DPRINTK("PCI1723: the pci1723_ao_write_winsn() ------\n"); 00228 00229 for (n = 0; n < insn->n; n++) { 00230 00231 devpriv->ao_data[chan] = data[n]; 00232 outw(data[n], dev->iobase + PCI1723_DA(chan)); 00233 } 00234 00235 return n; 00236 } 00237 00238 /* 00239 digital i/o config/query 00240 */ 00241 static int pci1723_dio_insn_config(comedi_device * dev, comedi_subdevice * s, 00242 comedi_insn * insn, lsampl_t * data) 00243 { 00244 unsigned int mask; 00245 unsigned int bits; 00246 unsigned short dio_mode; 00247 00248 mask = 1 << CR_CHAN(insn->chanspec); 00249 if (mask & 0x00FF) { 00250 bits = 0x00FF; 00251 } else { 00252 bits = 0xFF00; 00253 } 00254 switch (data[0]) { 00255 case INSN_CONFIG_DIO_INPUT: 00256 s->io_bits &= ~bits; 00257 break; 00258 case INSN_CONFIG_DIO_OUTPUT: 00259 s->io_bits |= bits; 00260 break; 00261 case INSN_CONFIG_DIO_QUERY: 00262 data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT; 00263 return insn->n; 00264 default: 00265 return -EINVAL; 00266 } 00267 00268 // update hardware DIO mode 00269 dio_mode = 0x0000; // low byte output, high byte output 00270 if ((s->io_bits & 0x00FF) == 0) 00271 dio_mode |= 0x0001; // low byte input 00272 if ((s->io_bits & 0xFF00) == 0) 00273 dio_mode |= 0x0002; // high byte input 00274 outw(dio_mode, dev->iobase + PCI1723_DIGITAL_IO_PORT_SET); 00275 return 1; 00276 } 00277 00278 /* 00279 digital i/o bits read/write 00280 */ 00281 static int pci1723_dio_insn_bits(comedi_device * dev, comedi_subdevice * s, 00282 comedi_insn * insn, lsampl_t * data) 00283 { 00284 if (data[0]) { 00285 s->state &= ~data[0]; 00286 s->state |= (data[0] & data[1]); 00287 outw(s->state, dev->iobase + PCI1723_WRITE_DIGITAL_OUTPUT_CMD); 00288 } 00289 data[1] = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA); 00290 return 2; 00291 } 00292 00293 /* 00294 * Attach is called by the Comedi core to configure the driver 00295 * for a pci1723 board. 00296 */ 00297 static int pci1723_attach(comedi_device * dev, comedi_devconfig * it) 00298 { 00299 comedi_subdevice *s; 00300 int ret, subdev, n_subdevices; 00301 struct pci_dev *pcidev; 00302 unsigned int iobase; 00303 unsigned char pci_bus, pci_slot, pci_func; 00304 int opt_bus, opt_slot; 00305 const char *errstr; 00306 00307 rt_printk("comedi%d: adv_pci1723: board=%s", dev->minor, 00308 this_board->name); 00309 00310 opt_bus = it->options[0]; 00311 opt_slot = it->options[1]; 00312 00313 if ((ret = alloc_private(dev, sizeof(pci1723_private))) < 0) { 00314 rt_printk(" - Allocation failed!\n"); 00315 return -ENOMEM; 00316 } 00317 00318 /* Look for matching PCI device */ 00319 errstr = "not found!"; 00320 pcidev = NULL; 00321 while (NULL != (pcidev = 00322 pci_get_device(PCI_VENDOR_ID_ADVANTECH, 00323 this_board->device_id, pcidev))) { 00324 /* Found matching vendor/device. */ 00325 if (opt_bus || opt_slot) { 00326 /* Check bus/slot. */ 00327 if (opt_bus != pcidev->bus->number 00328 || opt_slot != PCI_SLOT(pcidev->devfn)) 00329 continue; /* no match */ 00330 } 00331 /* 00332 * Look for device that isn't in use. 00333 * Enable PCI device and request regions. 00334 */ 00335 if (comedi_pci_enable(pcidev, "adv_pci1723")) { 00336 errstr = "failed to enable PCI device and request regions!"; 00337 continue; 00338 } 00339 break; 00340 } 00341 00342 if (!pcidev) { 00343 if (opt_bus || opt_slot) { 00344 rt_printk(" - Card at b:s %d:%d %s\n", 00345 opt_bus, opt_slot, errstr); 00346 } else { 00347 rt_printk(" - Card %s\n", errstr); 00348 } 00349 return -EIO; 00350 } 00351 00352 pci_bus = pcidev->bus->number; 00353 pci_slot = PCI_SLOT(pcidev->devfn); 00354 pci_func = PCI_FUNC(pcidev->devfn); 00355 iobase = pci_resource_start(pcidev, 2); 00356 00357 rt_printk(", b:s:f=%d:%d:%d, io=0x%4x", pci_bus, pci_slot, pci_func, 00358 iobase); 00359 00360 dev->iobase = iobase; 00361 00362 dev->board_name = this_board->name; 00363 devpriv->pcidev = pcidev; 00364 00365 n_subdevices = 0; 00366 00367 if (this_board->n_aochan) 00368 n_subdevices++; 00369 if (this_board->n_diochan) 00370 n_subdevices++; 00371 00372 if ((ret = alloc_subdevices(dev, n_subdevices)) < 0) { 00373 rt_printk(" - Allocation failed!\n"); 00374 return ret; 00375 } 00376 00377 pci1723_reset(dev); 00378 subdev = 0; 00379 if (this_board->n_aochan) { 00380 s = dev->subdevices + subdev; 00381 dev->write_subdev = s; 00382 s->type = COMEDI_SUBD_AO; 00383 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; 00384 s->n_chan = this_board->n_aochan; 00385 s->maxdata = this_board->ao_maxdata; 00386 s->len_chanlist = this_board->n_aochan; 00387 s->range_table = this_board->rangelist_ao; 00388 00389 s->insn_write = pci1723_ao_write_winsn; 00390 s->insn_read = pci1723_insn_read_ao; 00391 00392 // read DIO config 00393 switch (inw(dev->iobase + PCI1723_DIGITAL_IO_PORT_MODE) & 0x03) { 00394 case 0x00: // low byte output, high byte output 00395 s->io_bits = 0xFFFF; 00396 break; 00397 case 0x01: // low byte input, high byte output 00398 s->io_bits = 0xFF00; 00399 break; 00400 case 0x02: // low byte output, high byte input 00401 s->io_bits = 0x00FF; 00402 break; 00403 case 0x03: // low byte input, high byte input 00404 s->io_bits = 0x0000; 00405 break; 00406 } 00407 // read DIO port state 00408 s->state = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA); 00409 00410 subdev++; 00411 } 00412 00413 if (this_board->n_diochan) { 00414 s = dev->subdevices + subdev; 00415 s->type = COMEDI_SUBD_DIO; 00416 s->subdev_flags = 00417 SDF_READABLE | SDF_WRITABLE | SDF_GROUND | SDF_COMMON; 00418 s->n_chan = this_board->n_diochan; 00419 s->maxdata = 1; 00420 s->len_chanlist = this_board->n_diochan; 00421 s->range_table = &range_digital; 00422 s->insn_config = pci1723_dio_insn_config; 00423 s->insn_bits = pci1723_dio_insn_bits; 00424 subdev++; 00425 } 00426 00427 devpriv->valid = 1; 00428 00429 pci1723_reset(dev); 00430 00431 return 0; 00432 } 00433 00434 /* 00435 * _detach is called to deconfigure a device. It should deallocate 00436 * resources. 00437 * This function is also called when _attach() fails, so it should be 00438 * careful not to release resources that were not necessarily 00439 * allocated by _attach(). dev->private and dev->subdevices are 00440 * deallocated automatically by the core. 00441 */ 00442 static int pci1723_detach(comedi_device * dev) 00443 { 00444 printk("comedi%d: pci1723: remove\n", dev->minor); 00445 00446 if (dev->private) { 00447 if (devpriv->valid) 00448 pci1723_reset(dev); 00449 00450 if (devpriv->pcidev) { 00451 if (dev->iobase) { 00452 comedi_pci_disable(devpriv->pcidev); 00453 } 00454 pci_dev_put(devpriv->pcidev); 00455 } 00456 } 00457 00458 return 0; 00459 } 00460 00461 /* 00462 * A convenient macro that defines init_module() and cleanup_module(), 00463 * as necessary. 00464 */ 00465 COMEDI_PCI_INITCLEANUP(driver_pci1723, pci1723_pci_table);