adv_pci_dio.c revision d4da77a73cb9cc9a1a349daa1a2723505b086e2d
1/* 2 * comedi/drivers/adv_pci_dio.c 3 * 4 * Author: Michal Dobes <dobes@tesnet.cz> 5 * 6 * Hardware driver for Advantech PCI DIO cards. 7*/ 8/* 9Driver: adv_pci_dio 10Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1735U, 11 PCI-1736UP, PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, 12 PCI-1754, PCI-1756, PCI-1762 13Author: Michal Dobes <dobes@tesnet.cz> 14Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733, 15 PCI-1734, PCI-1735U, PCI-1736UP, PCI-1750, 16 PCI-1751, PCI-1752, PCI-1753, 17 PCI-1753+PCI-1753E, PCI-1754, PCI-1756, 18 PCI-1760, PCI-1762 19Status: untested 20Updated: Tue, 04 May 2010 13:00:00 +0000 21 22This driver supports now only insn interface for DI/DO/DIO. 23 24Configuration options: 25 [0] - PCI bus of device (optional) 26 [1] - PCI slot of device (optional) 27 If bus/slot is not specified, the first available PCI 28 device will be used. 29 30*/ 31 32#include "../comedidev.h" 33 34#include <linux/delay.h> 35 36#include "comedi_pci.h" 37#include "8255.h" 38#include "8253.h" 39 40#undef PCI_DIO_EXTDEBUG /* if defined, enable extensive debug logging */ 41 42#undef DPRINTK 43#ifdef PCI_DIO_EXTDEBUG 44#define DPRINTK(fmt, args...) printk(fmt, ## args) 45#else 46#define DPRINTK(fmt, args...) 47#endif 48 49#define PCI_VENDOR_ID_ADVANTECH 0x13fe 50 51/* hardware types of the cards */ 52enum hw_cards_id { 53 TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1735, TYPE_PCI1736, 54 TYPE_PCI1750, 55 TYPE_PCI1751, 56 TYPE_PCI1752, 57 TYPE_PCI1753, TYPE_PCI1753E, 58 TYPE_PCI1754, TYPE_PCI1756, 59 TYPE_PCI1760, 60 TYPE_PCI1762 61}; 62 63/* which I/O instructions to use */ 64enum hw_io_access { 65 IO_8b, IO_16b 66}; 67 68#define MAX_DI_SUBDEVS 2 /* max number of DI subdevices per card */ 69#define MAX_DO_SUBDEVS 2 /* max number of DO subdevices per card */ 70#define MAX_DIO_SUBDEVG 2 /* max number of DIO subdevices group per card */ 71#define MAX_8254_SUBDEVS 1 /* max number of 8254 counter subdevs per card */ 72 /* (could be more than one 8254 per subdevice) */ 73 74#define SIZE_8254 4 /* 8254 IO space length */ 75#define SIZE_8255 4 /* 8255 IO space length */ 76 77#define PCIDIO_MAINREG 2 /* main I/O region for all Advantech cards? */ 78 79/* Register offset definitions */ 80/* Advantech PCI-1730/3/4 */ 81#define PCI1730_IDI 0 /* R: Isolated digital input 0-15 */ 82#define PCI1730_IDO 0 /* W: Isolated digital output 0-15 */ 83#define PCI1730_DI 2 /* R: Digital input 0-15 */ 84#define PCI1730_DO 2 /* W: Digital output 0-15 */ 85#define PCI1733_IDI 0 /* R: Isolated digital input 0-31 */ 86#define PCI1730_3_INT_EN 0x08 /* R/W: enable/disable interrupts */ 87#define PCI1730_3_INT_RF 0x0c /* R/W: set falling/raising edge for interrupts */ 88#define PCI1730_3_INT_CLR 0x10 /* R/W: clear interrupts */ 89#define PCI1734_IDO 0 /* W: Isolated digital output 0-31 */ 90#define PCI173x_BOARDID 4 /* R: Board I/D switch for 1730/3/4 */ 91 92/* Advantech PCI-1735U */ 93#define PCI1735_DI 0 /* R: Digital input 0-31 */ 94#define PCI1735_DO 0 /* W: Digital output 0-31 */ 95#define PCI1735_C8254 4 /* R/W: 8254 counter */ 96#define PCI1735_BOARDID 8 /* R: Board I/D switch for 1735U */ 97 98/* Advantech PCI-1736UP */ 99#define PCI1736_IDI 0 /* R: Isolated digital input 0-15 */ 100#define PCI1736_IDO 0 /* W: Isolated digital output 0-15 */ 101#define PCI1736_3_INT_EN 0x08 /* R/W: enable/disable interrupts */ 102#define PCI1736_3_INT_RF 0x0c /* R/W: set falling/raising edge for interrupts */ 103#define PCI1736_3_INT_CLR 0x10 /* R/W: clear interrupts */ 104#define PCI1736_BOARDID 4 /* R: Board I/D switch for 1736UP */ 105#define PCI1736_MAINREG 0 /* Normal register (2) doesn't work */ 106 107/* Advantech PCI-1750 */ 108#define PCI1750_IDI 0 /* R: Isolated digital input 0-15 */ 109#define PCI1750_IDO 0 /* W: Isolated digital output 0-15 */ 110#define PCI1750_ICR 32 /* W: Interrupt control register */ 111#define PCI1750_ISR 32 /* R: Interrupt status register */ 112 113/* Advantech PCI-1751/3/3E */ 114#define PCI1751_DIO 0 /* R/W: begin of 8255 registers block */ 115#define PCI1751_ICR 32 /* W: Interrupt control register */ 116#define PCI1751_ISR 32 /* R: Interrupt status register */ 117#define PCI1753_DIO 0 /* R/W: begin of 8255 registers block */ 118#define PCI1753_ICR0 16 /* R/W: Interrupt control register group 0 */ 119#define PCI1753_ICR1 17 /* R/W: Interrupt control register group 1 */ 120#define PCI1753_ICR2 18 /* R/W: Interrupt control register group 2 */ 121#define PCI1753_ICR3 19 /* R/W: Interrupt control register group 3 */ 122#define PCI1753E_DIO 32 /* R/W: begin of 8255 registers block */ 123#define PCI1753E_ICR0 48 /* R/W: Interrupt control register group 0 */ 124#define PCI1753E_ICR1 49 /* R/W: Interrupt control register group 1 */ 125#define PCI1753E_ICR2 50 /* R/W: Interrupt control register group 2 */ 126#define PCI1753E_ICR3 51 /* R/W: Interrupt control register group 3 */ 127 128/* Advantech PCI-1752/4/6 */ 129#define PCI1752_IDO 0 /* R/W: Digital output 0-31 */ 130#define PCI1752_IDO2 4 /* R/W: Digital output 32-63 */ 131#define PCI1754_IDI 0 /* R: Digital input 0-31 */ 132#define PCI1754_IDI2 4 /* R: Digital input 32-64 */ 133#define PCI1756_IDI 0 /* R: Digital input 0-31 */ 134#define PCI1756_IDO 4 /* R/W: Digital output 0-31 */ 135#define PCI1754_6_ICR0 0x08 /* R/W: Interrupt control register group 0 */ 136#define PCI1754_6_ICR1 0x0a /* R/W: Interrupt control register group 1 */ 137#define PCI1754_ICR2 0x0c /* R/W: Interrupt control register group 2 */ 138#define PCI1754_ICR3 0x0e /* R/W: Interrupt control register group 3 */ 139#define PCI1752_6_CFC 0x12 /* R/W: set/read channel freeze function */ 140#define PCI175x_BOARDID 0x10 /* R: Board I/D switch for 1752/4/6 */ 141 142/* Advantech PCI-1762 registers */ 143#define PCI1762_RO 0 /* R/W: Relays status/output */ 144#define PCI1762_IDI 2 /* R: Isolated input status */ 145#define PCI1762_BOARDID 4 /* R: Board I/D switch */ 146#define PCI1762_ICR 6 /* W: Interrupt control register */ 147#define PCI1762_ISR 6 /* R: Interrupt status register */ 148 149/* Advantech PCI-1760 registers */ 150#define OMB0 0x0c /* W: Mailbox outgoing registers */ 151#define OMB1 0x0d 152#define OMB2 0x0e 153#define OMB3 0x0f 154#define IMB0 0x1c /* R: Mailbox incoming registers */ 155#define IMB1 0x1d 156#define IMB2 0x1e 157#define IMB3 0x1f 158#define INTCSR0 0x38 /* R/W: Interrupt control registers */ 159#define INTCSR1 0x39 160#define INTCSR2 0x3a 161#define INTCSR3 0x3b 162 163/* PCI-1760 mailbox commands */ 164#define CMD_ClearIMB2 0x00 /* Clear IMB2 status and return actaul DI status in IMB3 */ 165#define CMD_SetRelaysOutput 0x01 /* Set relay output from OMB0 */ 166#define CMD_GetRelaysStatus 0x02 /* Get relay status to IMB0 */ 167#define CMD_ReadCurrentStatus 0x07 /* Read the current status of the register in OMB0, result in IMB0 */ 168#define CMD_ReadFirmwareVersion 0x0e /* Read the firmware ver., result in IMB1.IMB0 */ 169#define CMD_ReadHardwareVersion 0x0f /* Read the hardware ver., result in IMB1.IMB0 */ 170#define CMD_EnableIDIFilters 0x20 /* Enable IDI filters based on bits in OMB0 */ 171#define CMD_EnableIDIPatternMatch 0x21 /* Enable IDI pattern match based on bits in OMB0 */ 172#define CMD_SetIDIPatternMatch 0x22 /* Enable IDI pattern match based on bits in OMB0 */ 173#define CMD_EnableIDICounters 0x28 /* Enable IDI counters based on bits in OMB0 */ 174#define CMD_ResetIDICounters 0x29 /* Reset IDI counters based on bits in OMB0 to its reset values */ 175#define CMD_OverflowIDICounters 0x2a /* Enable IDI counters overflow interrupts based on bits in OMB0 */ 176#define CMD_MatchIntIDICounters 0x2b /* Enable IDI counters match value interrupts based on bits in OMB0 */ 177#define CMD_EdgeIDICounters 0x2c /* Set IDI up counters count edge (bit=0 - rising, =1 - falling) */ 178#define CMD_GetIDICntCurValue 0x2f /* Read IDI{OMB0} up counter current value */ 179#define CMD_SetIDI0CntResetValue 0x40 /* Set IDI0 Counter Reset Value 256*OMB1+OMB0 */ 180#define CMD_SetIDI1CntResetValue 0x41 /* Set IDI1 Counter Reset Value 256*OMB1+OMB0 */ 181#define CMD_SetIDI2CntResetValue 0x42 /* Set IDI2 Counter Reset Value 256*OMB1+OMB0 */ 182#define CMD_SetIDI3CntResetValue 0x43 /* Set IDI3 Counter Reset Value 256*OMB1+OMB0 */ 183#define CMD_SetIDI4CntResetValue 0x44 /* Set IDI4 Counter Reset Value 256*OMB1+OMB0 */ 184#define CMD_SetIDI5CntResetValue 0x45 /* Set IDI5 Counter Reset Value 256*OMB1+OMB0 */ 185#define CMD_SetIDI6CntResetValue 0x46 /* Set IDI6 Counter Reset Value 256*OMB1+OMB0 */ 186#define CMD_SetIDI7CntResetValue 0x47 /* Set IDI7 Counter Reset Value 256*OMB1+OMB0 */ 187#define CMD_SetIDI0CntMatchValue 0x48 /* Set IDI0 Counter Match Value 256*OMB1+OMB0 */ 188#define CMD_SetIDI1CntMatchValue 0x49 /* Set IDI1 Counter Match Value 256*OMB1+OMB0 */ 189#define CMD_SetIDI2CntMatchValue 0x4a /* Set IDI2 Counter Match Value 256*OMB1+OMB0 */ 190#define CMD_SetIDI3CntMatchValue 0x4b /* Set IDI3 Counter Match Value 256*OMB1+OMB0 */ 191#define CMD_SetIDI4CntMatchValue 0x4c /* Set IDI4 Counter Match Value 256*OMB1+OMB0 */ 192#define CMD_SetIDI5CntMatchValue 0x4d /* Set IDI5 Counter Match Value 256*OMB1+OMB0 */ 193#define CMD_SetIDI6CntMatchValue 0x4e /* Set IDI6 Counter Match Value 256*OMB1+OMB0 */ 194#define CMD_SetIDI7CntMatchValue 0x4f /* Set IDI7 Counter Match Value 256*OMB1+OMB0 */ 195 196#define OMBCMD_RETRY 0x03 /* 3 times try request before error */ 197 198static int pci_dio_attach(struct comedi_device *dev, 199 struct comedi_devconfig *it); 200static int pci_dio_detach(struct comedi_device *dev); 201 202struct diosubd_data { 203 int chans; /* num of chans */ 204 int addr; /* PCI address ofset */ 205 int regs; /* number of registers to read or 8255 206 subdevices or 8254 chips */ 207 unsigned int specflags; /* addon subdevice flags */ 208}; 209 210struct dio_boardtype { 211 const char *name; /* board name */ 212 int vendor_id; /* vendor/device PCI ID */ 213 int device_id; 214 int main_pci_region; /* main I/O PCI region */ 215 enum hw_cards_id cardtype; 216 struct diosubd_data sdi[MAX_DI_SUBDEVS]; /* DI chans */ 217 struct diosubd_data sdo[MAX_DO_SUBDEVS]; /* DO chans */ 218 struct diosubd_data sdio[MAX_DIO_SUBDEVG]; /* DIO 8255 chans */ 219 struct diosubd_data boardid; /* card supports board ID switch */ 220 struct diosubd_data s8254[MAX_8254_SUBDEVS]; /* 8254 subdevices */ 221 enum hw_io_access io_access; 222}; 223 224static DEFINE_PCI_DEVICE_TABLE(pci_dio_pci_table) = { 225 { 226 PCI_VENDOR_ID_ADVANTECH, 0x1730, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 227 PCI_VENDOR_ID_ADVANTECH, 0x1733, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 228 PCI_VENDOR_ID_ADVANTECH, 0x1734, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 229 PCI_VENDOR_ID_ADVANTECH, 0x1735, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 230 PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 231 PCI_VENDOR_ID_ADVANTECH, 0x1750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 232 PCI_VENDOR_ID_ADVANTECH, 0x1751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 233 PCI_VENDOR_ID_ADVANTECH, 0x1752, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 234 PCI_VENDOR_ID_ADVANTECH, 0x1753, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 235 PCI_VENDOR_ID_ADVANTECH, 0x1754, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 236 PCI_VENDOR_ID_ADVANTECH, 0x1756, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 237 PCI_VENDOR_ID_ADVANTECH, 0x1760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 238 PCI_VENDOR_ID_ADVANTECH, 0x1762, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 239 0} 240}; 241 242MODULE_DEVICE_TABLE(pci, pci_dio_pci_table); 243 244static const struct dio_boardtype boardtypes[] = { 245 {"pci1730", PCI_VENDOR_ID_ADVANTECH, 0x1730, PCIDIO_MAINREG, 246 TYPE_PCI1730, 247 {{16, PCI1730_DI, 2, 0}, {16, PCI1730_IDI, 2, 0}}, 248 {{16, PCI1730_DO, 2, 0}, {16, PCI1730_IDO, 2, 0}}, 249 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 250 {4, PCI173x_BOARDID, 1, SDF_INTERNAL}, 251 {{0, 0, 0, 0}}, 252 IO_8b}, 253 {"pci1733", PCI_VENDOR_ID_ADVANTECH, 0x1733, PCIDIO_MAINREG, 254 TYPE_PCI1733, 255 {{0, 0, 0, 0}, {32, PCI1733_IDI, 4, 0}}, 256 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 257 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 258 {4, PCI173x_BOARDID, 1, SDF_INTERNAL}, 259 {{0, 0, 0, 0}}, 260 IO_8b}, 261 {"pci1734", PCI_VENDOR_ID_ADVANTECH, 0x1734, PCIDIO_MAINREG, 262 TYPE_PCI1734, 263 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 264 {{0, 0, 0, 0}, {32, PCI1734_IDO, 4, 0}}, 265 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 266 {4, PCI173x_BOARDID, 1, SDF_INTERNAL}, 267 {{0, 0, 0, 0}}, 268 IO_8b}, 269 {"pci1735", PCI_VENDOR_ID_ADVANTECH, 0x1735, PCIDIO_MAINREG, 270 TYPE_PCI1735, 271 {{32, PCI1735_DI, 4, 0}, {0, 0, 0, 0}}, 272 {{32, PCI1735_DO, 4, 0}, {0, 0, 0, 0}}, 273 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 274 { 4, PCI1735_BOARDID, 1, SDF_INTERNAL}, 275 {{3, PCI1735_C8254, 1, 0}}, 276 IO_8b}, 277 {"pci1736", PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI1736_MAINREG, 278 TYPE_PCI1736, 279 {{0, 0, 0, 0}, {16, PCI1736_IDI, 2, 0}}, 280 {{0, 0, 0, 0}, {16, PCI1736_IDO, 2, 0}}, 281 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 282 {4, PCI1736_BOARDID, 1, SDF_INTERNAL}, 283 {{0, 0, 0, 0}}, 284 IO_8b}, 285 {"pci1750", PCI_VENDOR_ID_ADVANTECH, 0x1750, PCIDIO_MAINREG, 286 TYPE_PCI1750, 287 {{0, 0, 0, 0}, {16, PCI1750_IDI, 2, 0}}, 288 {{0, 0, 0, 0}, {16, PCI1750_IDO, 2, 0}}, 289 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 290 {0, 0, 0, 0}, 291 {{0, 0, 0, 0}}, 292 IO_8b}, 293 {"pci1751", PCI_VENDOR_ID_ADVANTECH, 0x1751, PCIDIO_MAINREG, 294 TYPE_PCI1751, 295 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 296 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 297 {{48, PCI1751_DIO, 2, 0}, {0, 0, 0, 0}}, 298 {0, 0, 0, 0}, 299 {{0, 0, 0, 0}}, 300 IO_8b}, 301 {"pci1752", PCI_VENDOR_ID_ADVANTECH, 0x1752, PCIDIO_MAINREG, 302 TYPE_PCI1752, 303 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 304 {{32, PCI1752_IDO, 2, 0}, {32, PCI1752_IDO2, 2, 0}}, 305 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 306 {4, PCI175x_BOARDID, 1, SDF_INTERNAL}, 307 {{0, 0, 0, 0}}, 308 IO_16b}, 309 {"pci1753", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG, 310 TYPE_PCI1753, 311 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 312 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 313 {{96, PCI1753_DIO, 4, 0}, {0, 0, 0, 0}}, 314 {0, 0, 0, 0}, 315 {{0, 0, 0, 0}}, 316 IO_8b}, 317 {"pci1753e", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG, 318 TYPE_PCI1753E, 319 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 320 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 321 {{96, PCI1753_DIO, 4, 0}, {96, PCI1753E_DIO, 4, 0}}, 322 {0, 0, 0, 0}, 323 {{0, 0, 0, 0}}, 324 IO_8b}, 325 {"pci1754", PCI_VENDOR_ID_ADVANTECH, 0x1754, PCIDIO_MAINREG, 326 TYPE_PCI1754, 327 {{32, PCI1754_IDI, 2, 0}, {32, PCI1754_IDI2, 2, 0}}, 328 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 329 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 330 {4, PCI175x_BOARDID, 1, SDF_INTERNAL}, 331 {{0, 0, 0, 0}}, 332 IO_16b}, 333 {"pci1756", PCI_VENDOR_ID_ADVANTECH, 0x1756, PCIDIO_MAINREG, 334 TYPE_PCI1756, 335 {{0, 0, 0, 0}, {32, PCI1756_IDI, 2, 0}}, 336 {{0, 0, 0, 0}, {32, PCI1756_IDO, 2, 0}}, 337 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 338 {4, PCI175x_BOARDID, 1, SDF_INTERNAL}, 339 {{0, 0, 0, 0}}, 340 IO_16b}, 341 {"pci1760", PCI_VENDOR_ID_ADVANTECH, 0x1760, 0, 342 TYPE_PCI1760, 343 {{0, 0, 0, 0}, {0, 0, 0, 0}}, /* This card have own setup work */ 344 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 345 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 346 {0, 0, 0, 0}, 347 {{0, 0, 0, 0}}, 348 IO_8b}, 349 {"pci1762", PCI_VENDOR_ID_ADVANTECH, 0x1762, PCIDIO_MAINREG, 350 TYPE_PCI1762, 351 {{0, 0, 0, 0}, {16, PCI1762_IDI, 1, 0}}, 352 {{0, 0, 0, 0}, {16, PCI1762_RO, 1, 0}}, 353 {{0, 0, 0, 0}, {0, 0, 0, 0}}, 354 {4, PCI1762_BOARDID, 1, SDF_INTERNAL}, 355 {{0, 0, 0, 0}}, 356 IO_16b} 357}; 358 359#define n_boardtypes (sizeof(boardtypes)/sizeof(struct dio_boardtype)) 360 361static struct comedi_driver driver_pci_dio = { 362 .driver_name = "adv_pci_dio", 363 .module = THIS_MODULE, 364 .attach = pci_dio_attach, 365 .detach = pci_dio_detach 366}; 367 368struct pci_dio_private { 369 struct pci_dio_private *prev; /* previous private struct */ 370 struct pci_dio_private *next; /* next private struct */ 371 struct pci_dev *pcidev; /* pointer to board's pci_dev */ 372 char valid; /* card is usable */ 373 char GlobalIrqEnabled; /* 1= any IRQ source is enabled */ 374 /* PCI-1760 specific data */ 375 unsigned char IDICntEnable; /* counter's counting enable status */ 376 unsigned char IDICntOverEnable; /* counter's overflow interrupts enable status */ 377 unsigned char IDICntMatchEnable; /* counter's match interrupts enable status */ 378 unsigned char IDICntEdge; /* counter's count edge value (bit=0 - rising, =1 - falling) */ 379 unsigned short CntResValue[8]; /* counters' reset value */ 380 unsigned short CntMatchValue[8]; /* counters' match interrupt value */ 381 unsigned char IDIFiltersEn; /* IDI's digital filters enable status */ 382 unsigned char IDIPatMatchEn; /* IDI's pattern match enable status */ 383 unsigned char IDIPatMatchValue; /* IDI's pattern match value */ 384 unsigned short IDIFiltrLow[8]; /* IDI's filter value low signal */ 385 unsigned short IDIFiltrHigh[8]; /* IDI's filter value high signal */ 386}; 387 388static struct pci_dio_private *pci_priv = NULL; /* list of allocated cards */ 389 390#define devpriv ((struct pci_dio_private *)dev->private) 391#define this_board ((const struct dio_boardtype *)dev->board_ptr) 392 393/* 394============================================================================== 395*/ 396static int pci_dio_insn_bits_di_b(struct comedi_device *dev, 397 struct comedi_subdevice *s, 398 struct comedi_insn *insn, unsigned int *data) 399{ 400 const struct diosubd_data *d = (const struct diosubd_data *)s->private; 401 int i; 402 403 data[1] = 0; 404 for (i = 0; i < d->regs; i++) 405 data[1] |= inb(dev->iobase + d->addr + i) << (8 * i); 406 407 408 return 2; 409} 410 411/* 412============================================================================== 413*/ 414static int pci_dio_insn_bits_di_w(struct comedi_device *dev, 415 struct comedi_subdevice *s, 416 struct comedi_insn *insn, unsigned int *data) 417{ 418 const struct diosubd_data *d = (const struct diosubd_data *)s->private; 419 int i; 420 421 data[1] = 0; 422 for (i = 0; i < d->regs; i++) 423 data[1] |= inw(dev->iobase + d->addr + 2 * i) << (16 * i); 424 425 return 2; 426} 427 428/* 429============================================================================== 430*/ 431static int pci_dio_insn_bits_do_b(struct comedi_device *dev, 432 struct comedi_subdevice *s, 433 struct comedi_insn *insn, unsigned int *data) 434{ 435 const struct diosubd_data *d = (const struct diosubd_data *)s->private; 436 int i; 437 438 if (data[0]) { 439 s->state &= ~data[0]; 440 s->state |= (data[0] & data[1]); 441 for (i = 0; i < d->regs; i++) 442 outb((s->state >> (8 * i)) & 0xff, 443 dev->iobase + d->addr + i); 444 } 445 data[1] = s->state; 446 447 return 2; 448} 449 450/* 451============================================================================== 452*/ 453static int pci_dio_insn_bits_do_w(struct comedi_device *dev, 454 struct comedi_subdevice *s, 455 struct comedi_insn *insn, unsigned int *data) 456{ 457 const struct diosubd_data *d = (const struct diosubd_data *)s->private; 458 int i; 459 460 if (data[0]) { 461 s->state &= ~data[0]; 462 s->state |= (data[0] & data[1]); 463 for (i = 0; i < d->regs; i++) 464 outw((s->state >> (16 * i)) & 0xffff, 465 dev->iobase + d->addr + 2 * i); 466 } 467 data[1] = s->state; 468 469 return 2; 470} 471 472/* 473============================================================================== 474*/ 475static int pci_8254_insn_read(struct comedi_device *dev, 476 struct comedi_subdevice *s, 477 struct comedi_insn *insn, unsigned int *data) 478{ 479 const struct diosubd_data *d = (const struct diosubd_data *)s->private; 480 unsigned int chan, chip, chipchan; 481 unsigned long flags; 482 483 chan = CR_CHAN(insn->chanspec); /* channel on subdevice */ 484 chip = chan / 3; /* chip on subdevice */ 485 chipchan = chan - (3 * chip); /* channel on chip on subdevice */ 486 spin_lock_irqsave(&s->spin_lock, flags); 487 data[0] = i8254_read(dev->iobase + d->addr + (SIZE_8254 * chip), 488 0, chipchan); 489 spin_unlock_irqrestore(&s->spin_lock, flags); 490 return 1; 491} 492 493/* 494============================================================================== 495*/ 496static int pci_8254_insn_write(struct comedi_device *dev, 497 struct comedi_subdevice *s, 498 struct comedi_insn *insn, unsigned int *data) 499{ 500 const struct diosubd_data *d = (const struct diosubd_data *)s->private; 501 unsigned int chan, chip, chipchan; 502 unsigned long flags; 503 504 chan = CR_CHAN(insn->chanspec); /* channel on subdevice */ 505 chip = chan / 3; /* chip on subdevice */ 506 chipchan = chan - (3 * chip); /* channel on chip on subdevice */ 507 spin_lock_irqsave(&s->spin_lock, flags); 508 i8254_write(dev->iobase + d->addr + (SIZE_8254 * chip), 509 0, chipchan, data[0]); 510 spin_unlock_irqrestore(&s->spin_lock, flags); 511 return 1; 512} 513 514/* 515============================================================================== 516*/ 517static int pci_8254_insn_config(struct comedi_device *dev, 518 struct comedi_subdevice *s, 519 struct comedi_insn *insn, unsigned int *data) 520{ 521 const struct diosubd_data *d = (const struct diosubd_data *)s->private; 522 unsigned int chan, chip, chipchan; 523 unsigned long iobase; 524 int ret = 0; 525 unsigned long flags; 526 527 chan = CR_CHAN(insn->chanspec); /* channel on subdevice */ 528 chip = chan / 3; /* chip on subdevice */ 529 chipchan = chan - (3 * chip); /* channel on chip on subdevice */ 530 iobase = dev->iobase + d->addr + (SIZE_8254 * chip); 531 spin_lock_irqsave(&s->spin_lock, flags); 532 switch (data[0]) { 533 case INSN_CONFIG_SET_COUNTER_MODE: 534 ret = i8254_set_mode(iobase, 0, chipchan, data[1]); 535 if (ret < 0) 536 ret = -EINVAL; 537 break; 538 case INSN_CONFIG_8254_READ_STATUS: 539 data[1] = i8254_status(iobase, 0, chipchan); 540 break; 541 default: 542 ret = -EINVAL; 543 break; 544 } 545 spin_unlock_irqrestore(&s->spin_lock, flags); 546 return ret < 0 ? ret : insn->n; 547} 548 549/* 550============================================================================== 551*/ 552static int pci1760_unchecked_mbxrequest(struct comedi_device *dev, 553 unsigned char *omb, unsigned char *imb, 554 int repeats) 555{ 556 int cnt, tout, ok = 0; 557 558 for (cnt = 0; cnt < repeats; cnt++) { 559 outb(omb[0], dev->iobase + OMB0); 560 outb(omb[1], dev->iobase + OMB1); 561 outb(omb[2], dev->iobase + OMB2); 562 outb(omb[3], dev->iobase + OMB3); 563 for (tout = 0; tout < 251; tout++) { 564 imb[2] = inb(dev->iobase + IMB2); 565 if (imb[2] == omb[2]) { 566 imb[0] = inb(dev->iobase + IMB0); 567 imb[1] = inb(dev->iobase + IMB1); 568 imb[3] = inb(dev->iobase + IMB3); 569 ok = 1; 570 break; 571 } 572 udelay(1); 573 } 574 if (ok) 575 return 0; 576 } 577 578 comedi_error(dev, "PCI-1760 mailbox request timeout!"); 579 return -ETIME; 580} 581 582static int pci1760_clear_imb2(struct comedi_device *dev) 583{ 584 unsigned char omb[4] = { 0x0, 0x0, CMD_ClearIMB2, 0x0 }; 585 unsigned char imb[4]; 586 /* check if imb2 is already clear */ 587 if (inb(dev->iobase + IMB2) == CMD_ClearIMB2) 588 return 0; 589 return pci1760_unchecked_mbxrequest(dev, omb, imb, OMBCMD_RETRY); 590} 591 592static int pci1760_mbxrequest(struct comedi_device *dev, 593 unsigned char *omb, unsigned char *imb) 594{ 595 if (omb[2] == CMD_ClearIMB2) { 596 comedi_error(dev, 597 "bug! this function should not be used for CMD_ClearIMB2 command"); 598 return -EINVAL; 599 } 600 if (inb(dev->iobase + IMB2) == omb[2]) { 601 int retval; 602 retval = pci1760_clear_imb2(dev); 603 if (retval < 0) 604 return retval; 605 } 606 return pci1760_unchecked_mbxrequest(dev, omb, imb, OMBCMD_RETRY); 607} 608 609/* 610============================================================================== 611*/ 612static int pci1760_insn_bits_di(struct comedi_device *dev, 613 struct comedi_subdevice *s, 614 struct comedi_insn *insn, unsigned int *data) 615{ 616 data[1] = inb(dev->iobase + IMB3); 617 618 return 2; 619} 620 621/* 622============================================================================== 623*/ 624static int pci1760_insn_bits_do(struct comedi_device *dev, 625 struct comedi_subdevice *s, 626 struct comedi_insn *insn, unsigned int *data) 627{ 628 int ret; 629 unsigned char omb[4] = { 630 0x00, 631 0x00, 632 CMD_SetRelaysOutput, 633 0x00 634 }; 635 unsigned char imb[4]; 636 637 if (data[0]) { 638 s->state &= ~data[0]; 639 s->state |= (data[0] & data[1]); 640 omb[0] = s->state; 641 ret = pci1760_mbxrequest(dev, omb, imb); 642 if (!ret) 643 return ret; 644 } 645 data[1] = s->state; 646 647 return 2; 648} 649 650/* 651============================================================================== 652*/ 653static int pci1760_insn_cnt_read(struct comedi_device *dev, 654 struct comedi_subdevice *s, 655 struct comedi_insn *insn, unsigned int *data) 656{ 657 int ret, n; 658 unsigned char omb[4] = { 659 CR_CHAN(insn->chanspec) & 0x07, 660 0x00, 661 CMD_GetIDICntCurValue, 662 0x00 663 }; 664 unsigned char imb[4]; 665 666 for (n = 0; n < insn->n; n++) { 667 ret = pci1760_mbxrequest(dev, omb, imb); 668 if (!ret) 669 return ret; 670 data[n] = (imb[1] << 8) + imb[0]; 671 } 672 673 return n; 674} 675 676/* 677============================================================================== 678*/ 679static int pci1760_insn_cnt_write(struct comedi_device *dev, 680 struct comedi_subdevice *s, 681 struct comedi_insn *insn, unsigned int *data) 682{ 683 int ret; 684 unsigned char chan = CR_CHAN(insn->chanspec) & 0x07; 685 unsigned char bitmask = 1 << chan; 686 unsigned char omb[4] = { 687 data[0] & 0xff, 688 (data[0] >> 8) & 0xff, 689 CMD_SetIDI0CntResetValue + chan, 690 0x00 691 }; 692 unsigned char imb[4]; 693 694 if (devpriv->CntResValue[chan] != (data[0] & 0xffff)) { /* Set reset value if different */ 695 ret = pci1760_mbxrequest(dev, omb, imb); 696 if (!ret) 697 return ret; 698 devpriv->CntResValue[chan] = data[0] & 0xffff; 699 } 700 701 omb[0] = bitmask; /* reset counter to it reset value */ 702 omb[2] = CMD_ResetIDICounters; 703 ret = pci1760_mbxrequest(dev, omb, imb); 704 if (!ret) 705 return ret; 706 707 if (!(bitmask & devpriv->IDICntEnable)) { /* start counter if it don't run */ 708 omb[0] = bitmask; 709 omb[2] = CMD_EnableIDICounters; 710 ret = pci1760_mbxrequest(dev, omb, imb); 711 if (!ret) 712 return ret; 713 devpriv->IDICntEnable |= bitmask; 714 } 715 return 1; 716} 717 718/* 719============================================================================== 720*/ 721static int pci1760_reset(struct comedi_device *dev) 722{ 723 int i; 724 unsigned char omb[4] = { 0x00, 0x00, 0x00, 0x00 }; 725 unsigned char imb[4]; 726 727 outb(0, dev->iobase + INTCSR0); /* disable IRQ */ 728 outb(0, dev->iobase + INTCSR1); 729 outb(0, dev->iobase + INTCSR2); 730 outb(0, dev->iobase + INTCSR3); 731 devpriv->GlobalIrqEnabled = 0; 732 733 omb[0] = 0x00; 734 omb[2] = CMD_SetRelaysOutput; /* reset relay outputs */ 735 pci1760_mbxrequest(dev, omb, imb); 736 737 omb[0] = 0x00; 738 omb[2] = CMD_EnableIDICounters; /* disable IDI up counters */ 739 pci1760_mbxrequest(dev, omb, imb); 740 devpriv->IDICntEnable = 0; 741 742 omb[0] = 0x00; 743 omb[2] = CMD_OverflowIDICounters; /* disable counters overflow interrupts */ 744 pci1760_mbxrequest(dev, omb, imb); 745 devpriv->IDICntOverEnable = 0; 746 747 omb[0] = 0x00; 748 omb[2] = CMD_MatchIntIDICounters; /* disable counters match value interrupts */ 749 pci1760_mbxrequest(dev, omb, imb); 750 devpriv->IDICntMatchEnable = 0; 751 752 omb[0] = 0x00; 753 omb[1] = 0x80; 754 for (i = 0; i < 8; i++) { /* set IDI up counters match value */ 755 omb[2] = CMD_SetIDI0CntMatchValue + i; 756 pci1760_mbxrequest(dev, omb, imb); 757 devpriv->CntMatchValue[i] = 0x8000; 758 } 759 760 omb[0] = 0x00; 761 omb[1] = 0x00; 762 for (i = 0; i < 8; i++) { /* set IDI up counters reset value */ 763 omb[2] = CMD_SetIDI0CntResetValue + i; 764 pci1760_mbxrequest(dev, omb, imb); 765 devpriv->CntResValue[i] = 0x0000; 766 } 767 768 omb[0] = 0xff; 769 omb[2] = CMD_ResetIDICounters; /* reset IDI up counters to reset values */ 770 pci1760_mbxrequest(dev, omb, imb); 771 772 omb[0] = 0x00; 773 omb[2] = CMD_EdgeIDICounters; /* set IDI up counters count edge */ 774 pci1760_mbxrequest(dev, omb, imb); 775 devpriv->IDICntEdge = 0x00; 776 777 omb[0] = 0x00; 778 omb[2] = CMD_EnableIDIFilters; /* disable all digital in filters */ 779 pci1760_mbxrequest(dev, omb, imb); 780 devpriv->IDIFiltersEn = 0x00; 781 782 omb[0] = 0x00; 783 omb[2] = CMD_EnableIDIPatternMatch; /* disable pattern matching */ 784 pci1760_mbxrequest(dev, omb, imb); 785 devpriv->IDIPatMatchEn = 0x00; 786 787 omb[0] = 0x00; 788 omb[2] = CMD_SetIDIPatternMatch; /* set pattern match value */ 789 pci1760_mbxrequest(dev, omb, imb); 790 devpriv->IDIPatMatchValue = 0x00; 791 792 return 0; 793} 794 795/* 796============================================================================== 797*/ 798static int pci_dio_reset(struct comedi_device *dev) 799{ 800 DPRINTK("adv_pci_dio EDBG: BGN: pci171x_reset(...)\n"); 801 802 switch (this_board->cardtype) { 803 case TYPE_PCI1730: 804 outb(0, dev->iobase + PCI1730_DO); /* clear outputs */ 805 outb(0, dev->iobase + PCI1730_DO + 1); 806 outb(0, dev->iobase + PCI1730_IDO); 807 outb(0, dev->iobase + PCI1730_IDO + 1); 808 /* NO break there! */ 809 case TYPE_PCI1733: 810 outb(0, dev->iobase + PCI1730_3_INT_EN); /* disable interrupts */ 811 outb(0x0f, dev->iobase + PCI1730_3_INT_CLR); /* clear interrupts */ 812 outb(0, dev->iobase + PCI1730_3_INT_RF); /* set rising edge trigger */ 813 break; 814 case TYPE_PCI1734: 815 outb(0, dev->iobase + PCI1734_IDO); /* clear outputs */ 816 outb(0, dev->iobase + PCI1734_IDO + 1); 817 outb(0, dev->iobase + PCI1734_IDO + 2); 818 outb(0, dev->iobase + PCI1734_IDO + 3); 819 break; 820 case TYPE_PCI1735: 821 outb(0, dev->iobase + PCI1735_DO); /* clear outputs */ 822 outb(0, dev->iobase + PCI1735_DO + 1); 823 outb(0, dev->iobase + PCI1735_DO + 2); 824 outb(0, dev->iobase + PCI1735_DO + 3); 825 i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 0, I8254_MODE0); 826 i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 1, I8254_MODE0); 827 i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 2, I8254_MODE0); 828 break; 829 830 case TYPE_PCI1736: 831 outb(0, dev->iobase + PCI1736_IDO); 832 outb(0, dev->iobase + PCI1736_IDO + 1); 833 outb(0, dev->iobase + PCI1736_3_INT_EN); /* disable interrupts */ 834 outb(0x0f, dev->iobase + PCI1736_3_INT_CLR); /* clear interrupts */ 835 outb(0, dev->iobase + PCI1736_3_INT_RF); /* set rising edge trigger */ 836 break; 837 838 case TYPE_PCI1750: 839 case TYPE_PCI1751: 840 outb(0x88, dev->iobase + PCI1750_ICR); /* disable & clear interrupts */ 841 break; 842 case TYPE_PCI1752: 843 outw(0, dev->iobase + PCI1752_6_CFC); /* disable channel freeze function */ 844 outw(0, dev->iobase + PCI1752_IDO); /* clear outputs */ 845 outw(0, dev->iobase + PCI1752_IDO + 2); 846 outw(0, dev->iobase + PCI1752_IDO2); 847 outw(0, dev->iobase + PCI1752_IDO2 + 2); 848 break; 849 case TYPE_PCI1753E: 850 outb(0x88, dev->iobase + PCI1753E_ICR0); /* disable & clear interrupts */ 851 outb(0x80, dev->iobase + PCI1753E_ICR1); 852 outb(0x80, dev->iobase + PCI1753E_ICR2); 853 outb(0x80, dev->iobase + PCI1753E_ICR3); 854 /* NO break there! */ 855 case TYPE_PCI1753: 856 outb(0x88, dev->iobase + PCI1753_ICR0); /* disable & clear interrupts */ 857 outb(0x80, dev->iobase + PCI1753_ICR1); 858 outb(0x80, dev->iobase + PCI1753_ICR2); 859 outb(0x80, dev->iobase + PCI1753_ICR3); 860 break; 861 case TYPE_PCI1754: 862 outw(0x08, dev->iobase + PCI1754_6_ICR0); /* disable and clear interrupts */ 863 outw(0x08, dev->iobase + PCI1754_6_ICR1); 864 outw(0x08, dev->iobase + PCI1754_ICR2); 865 outw(0x08, dev->iobase + PCI1754_ICR3); 866 break; 867 case TYPE_PCI1756: 868 outw(0, dev->iobase + PCI1752_6_CFC); /* disable channel freeze function */ 869 outw(0x08, dev->iobase + PCI1754_6_ICR0); /* disable and clear interrupts */ 870 outw(0x08, dev->iobase + PCI1754_6_ICR1); 871 outw(0, dev->iobase + PCI1756_IDO); /* clear outputs */ 872 outw(0, dev->iobase + PCI1756_IDO + 2); 873 break; 874 case TYPE_PCI1760: 875 pci1760_reset(dev); 876 break; 877 case TYPE_PCI1762: 878 outw(0x0101, dev->iobase + PCI1762_ICR); /* disable & clear interrupts */ 879 break; 880 } 881 882 DPRINTK("adv_pci_dio EDBG: END: pci171x_reset(...)\n"); 883 884 return 0; 885} 886 887/* 888============================================================================== 889*/ 890static int pci1760_attach(struct comedi_device *dev, 891 struct comedi_devconfig *it) 892{ 893 struct comedi_subdevice *s; 894 int subdev = 0; 895 896 s = dev->subdevices + subdev; 897 s->type = COMEDI_SUBD_DI; 898 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; 899 s->n_chan = 8; 900 s->maxdata = 1; 901 s->len_chanlist = 8; 902 s->range_table = &range_digital; 903 s->insn_bits = pci1760_insn_bits_di; 904 subdev++; 905 906 s = dev->subdevices + subdev; 907 s->type = COMEDI_SUBD_DO; 908 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; 909 s->n_chan = 8; 910 s->maxdata = 1; 911 s->len_chanlist = 8; 912 s->range_table = &range_digital; 913 s->state = 0; 914 s->insn_bits = pci1760_insn_bits_do; 915 subdev++; 916 917 s = dev->subdevices + subdev; 918 s->type = COMEDI_SUBD_TIMER; 919 s->subdev_flags = SDF_WRITABLE | SDF_LSAMPL; 920 s->n_chan = 2; 921 s->maxdata = 0xffffffff; 922 s->len_chanlist = 2; 923/* s->insn_config=pci1760_insn_pwm_cfg; */ 924 subdev++; 925 926 s = dev->subdevices + subdev; 927 s->type = COMEDI_SUBD_COUNTER; 928 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 929 s->n_chan = 8; 930 s->maxdata = 0xffff; 931 s->len_chanlist = 8; 932 s->insn_read = pci1760_insn_cnt_read; 933 s->insn_write = pci1760_insn_cnt_write; 934/* s->insn_config=pci1760_insn_cnt_cfg; */ 935 subdev++; 936 937 return 0; 938} 939 940/* 941============================================================================== 942*/ 943static int pci_dio_add_di(struct comedi_device *dev, struct comedi_subdevice *s, 944 const struct diosubd_data *d, int subdev) 945{ 946 s->type = COMEDI_SUBD_DI; 947 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | d->specflags; 948 if (d->chans > 16) 949 s->subdev_flags |= SDF_LSAMPL; 950 s->n_chan = d->chans; 951 s->maxdata = 1; 952 s->len_chanlist = d->chans; 953 s->range_table = &range_digital; 954 switch (this_board->io_access) { 955 case IO_8b: 956 s->insn_bits = pci_dio_insn_bits_di_b; 957 break; 958 case IO_16b: 959 s->insn_bits = pci_dio_insn_bits_di_w; 960 break; 961 } 962 s->private = (void *)d; 963 964 return 0; 965} 966 967/* 968============================================================================== 969*/ 970static int pci_dio_add_do(struct comedi_device *dev, struct comedi_subdevice *s, 971 const struct diosubd_data *d, int subdev) 972{ 973 s->type = COMEDI_SUBD_DO; 974 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; 975 if (d->chans > 16) 976 s->subdev_flags |= SDF_LSAMPL; 977 s->n_chan = d->chans; 978 s->maxdata = 1; 979 s->len_chanlist = d->chans; 980 s->range_table = &range_digital; 981 s->state = 0; 982 switch (this_board->io_access) { 983 case IO_8b: 984 s->insn_bits = pci_dio_insn_bits_do_b; 985 break; 986 case IO_16b: 987 s->insn_bits = pci_dio_insn_bits_do_w; 988 break; 989 } 990 s->private = (void *)d; 991 992 return 0; 993} 994 995/* 996============================================================================== 997*/ 998static int pci_dio_add_8254(struct comedi_device *dev, 999 struct comedi_subdevice * s, 1000 const struct diosubd_data *d, int subdev) 1001{ 1002 s->type = COMEDI_SUBD_COUNTER; 1003 s->subdev_flags = SDF_WRITABLE | SDF_READABLE; 1004 s->n_chan = d->chans; 1005 s->maxdata = 65535; 1006 s->len_chanlist = d->chans; 1007 s->insn_read = pci_8254_insn_read; 1008 s->insn_write = pci_8254_insn_write; 1009 s->insn_config = pci_8254_insn_config; 1010 s->private = (void *)d; 1011 1012 return 0; 1013} 1014 1015/* 1016============================================================================== 1017*/ 1018static int CheckAndAllocCard(struct comedi_device *dev, 1019 struct comedi_devconfig *it, 1020 struct pci_dev *pcidev) 1021{ 1022 struct pci_dio_private *pr, *prev; 1023 1024 for (pr = pci_priv, prev = NULL; pr != NULL; prev = pr, pr = pr->next) { 1025 if (pr->pcidev == pcidev) 1026 return 0; /* this card is used, look for another */ 1027 1028 } 1029 1030 if (prev) { 1031 devpriv->prev = prev; 1032 prev->next = devpriv; 1033 } else { 1034 pci_priv = devpriv; 1035 } 1036 1037 devpriv->pcidev = pcidev; 1038 1039 return 1; 1040} 1041 1042/* 1043============================================================================== 1044*/ 1045static int pci_dio_attach(struct comedi_device *dev, 1046 struct comedi_devconfig *it) 1047{ 1048 struct comedi_subdevice *s; 1049 int ret, subdev, n_subdevices, i, j; 1050 unsigned long iobase; 1051 struct pci_dev *pcidev; 1052 1053 printk("comedi%d: adv_pci_dio: ", dev->minor); 1054 1055 ret = alloc_private(dev, sizeof(struct pci_dio_private)); 1056 if (ret < 0) { 1057 printk(", Error: Cann't allocate private memory!\n"); 1058 return -ENOMEM; 1059 } 1060 1061 for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); 1062 pcidev != NULL; 1063 pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) { 1064 /* loop through cards supported by this driver */ 1065 for (i = 0; i < n_boardtypes; ++i) { 1066 if (boardtypes[i].vendor_id != pcidev->vendor) 1067 continue; 1068 if (boardtypes[i].device_id != pcidev->device) 1069 continue; 1070 /* was a particular bus/slot requested? */ 1071 if (it->options[0] || it->options[1]) { 1072 /* are we on the wrong bus/slot? */ 1073 if (pcidev->bus->number != it->options[0] || 1074 PCI_SLOT(pcidev->devfn) != it->options[1]) { 1075 continue; 1076 } 1077 } 1078 ret = CheckAndAllocCard(dev, it, pcidev); 1079 if (ret != 1) 1080 continue; 1081 dev->board_ptr = boardtypes + i; 1082 break; 1083 } 1084 if (dev->board_ptr) 1085 break; 1086 } 1087 1088 if (!dev->board_ptr) { 1089 printk(", Error: Requested type of the card was not found!\n"); 1090 return -EIO; 1091 } 1092 1093 if (comedi_pci_enable(pcidev, driver_pci_dio.driver_name)) { 1094 printk 1095 (", Error: Can't enable PCI device and request regions!\n"); 1096 return -EIO; 1097 } 1098 iobase = pci_resource_start(pcidev, this_board->main_pci_region); 1099 printk(", b:s:f=%d:%d:%d, io=0x%4lx", 1100 pcidev->bus->number, PCI_SLOT(pcidev->devfn), 1101 PCI_FUNC(pcidev->devfn), iobase); 1102 1103 dev->iobase = iobase; 1104 dev->board_name = this_board->name; 1105 1106 if (this_board->cardtype == TYPE_PCI1760) { 1107 n_subdevices = 4; /* 8 IDI, 8 IDO, 2 PWM, 8 CNT */ 1108 } else { 1109 n_subdevices = 0; 1110 for (i = 0; i < MAX_DI_SUBDEVS; i++) 1111 if (this_board->sdi[i].chans) 1112 n_subdevices++; 1113 for (i = 0; i < MAX_DO_SUBDEVS; i++) 1114 if (this_board->sdo[i].chans) 1115 n_subdevices++; 1116 for (i = 0; i < MAX_DIO_SUBDEVG; i++) 1117 n_subdevices += this_board->sdio[i].regs; 1118 if (this_board->boardid.chans) 1119 n_subdevices++; 1120 for (i = 0; i < MAX_8254_SUBDEVS; i++) 1121 if (this_board->s8254[i].chans) 1122 n_subdevices++; 1123 } 1124 1125 ret = alloc_subdevices(dev, n_subdevices); 1126 if (ret < 0) { 1127 printk(", Error: Cann't allocate subdevice memory!\n"); 1128 return ret; 1129 } 1130 1131 printk(".\n"); 1132 1133 subdev = 0; 1134 1135 for (i = 0; i < MAX_DI_SUBDEVS; i++) 1136 if (this_board->sdi[i].chans) { 1137 s = dev->subdevices + subdev; 1138 pci_dio_add_di(dev, s, &this_board->sdi[i], subdev); 1139 subdev++; 1140 } 1141 1142 for (i = 0; i < MAX_DO_SUBDEVS; i++) 1143 if (this_board->sdo[i].chans) { 1144 s = dev->subdevices + subdev; 1145 pci_dio_add_do(dev, s, &this_board->sdo[i], subdev); 1146 subdev++; 1147 } 1148 1149 for (i = 0; i < MAX_DIO_SUBDEVG; i++) 1150 for (j = 0; j < this_board->sdio[i].regs; j++) { 1151 s = dev->subdevices + subdev; 1152 subdev_8255_init(dev, s, NULL, 1153 dev->iobase + 1154 this_board->sdio[i].addr + 1155 SIZE_8255 * j); 1156 subdev++; 1157 } 1158 1159 if (this_board->boardid.chans) { 1160 s = dev->subdevices + subdev; 1161 s->type = COMEDI_SUBD_DI; 1162 pci_dio_add_di(dev, s, &this_board->boardid, subdev); 1163 subdev++; 1164 } 1165 1166 for (i = 0; i < MAX_8254_SUBDEVS; i++) 1167 if (this_board->s8254[i].chans) { 1168 s = dev->subdevices + subdev; 1169 pci_dio_add_8254(dev, s, &this_board->s8254[i], subdev); 1170 subdev++; 1171 } 1172 1173 if (this_board->cardtype == TYPE_PCI1760) 1174 pci1760_attach(dev, it); 1175 1176 devpriv->valid = 1; 1177 1178 pci_dio_reset(dev); 1179 1180 return 0; 1181} 1182 1183/* 1184============================================================================== 1185*/ 1186static int pci_dio_detach(struct comedi_device *dev) 1187{ 1188 int i, j; 1189 struct comedi_subdevice *s; 1190 int subdev; 1191 1192 if (dev->private) { 1193 if (devpriv->valid) 1194 pci_dio_reset(dev); 1195 1196 1197 /* This shows the silliness of using this kind of 1198 * scheme for numbering subdevices. Don't do it. --ds */ 1199 subdev = 0; 1200 for (i = 0; i < MAX_DI_SUBDEVS; i++) { 1201 if (this_board->sdi[i].chans) 1202 subdev++; 1203 1204 } 1205 for (i = 0; i < MAX_DO_SUBDEVS; i++) { 1206 if (this_board->sdo[i].chans) 1207 subdev++; 1208 1209 } 1210 for (i = 0; i < MAX_DIO_SUBDEVG; i++) { 1211 for (j = 0; j < this_board->sdio[i].regs; j++) { 1212 s = dev->subdevices + subdev; 1213 subdev_8255_cleanup(dev, s); 1214 subdev++; 1215 } 1216 } 1217 1218 if (this_board->boardid.chans) { 1219 subdev++; 1220 } 1221 1222 for (i = 0; i < MAX_8254_SUBDEVS; i++) { 1223 if (this_board->s8254[i].chans) { 1224 subdev++; 1225 } 1226 } 1227 1228 for (i = 0; i < dev->n_subdevices; i++) { 1229 s = dev->subdevices + i; 1230 s->private = NULL; 1231 } 1232 1233 if (devpriv->pcidev) { 1234 if (dev->iobase) 1235 comedi_pci_disable(devpriv->pcidev); 1236 1237 pci_dev_put(devpriv->pcidev); 1238 } 1239 1240 if (devpriv->prev) 1241 devpriv->prev->next = devpriv->next; 1242 else 1243 pci_priv = devpriv->next; 1244 1245 if (devpriv->next) 1246 devpriv->next->prev = devpriv->prev; 1247 1248 } 1249 1250 return 0; 1251} 1252 1253/* 1254============================================================================== 1255*/ 1256COMEDI_PCI_INITCLEANUP(driver_pci_dio, pci_dio_pci_table); 1257/* 1258============================================================================== 1259*/ 1260