hwdrv_apci2032.c revision 356cdbcb838ebcc234a43ec81621a39231fdcb7a
1/** 2@verbatim 3 4Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. 5 6 ADDI-DATA GmbH 7 Dieselstrasse 3 8 D-77833 Ottersweier 9 Tel: +19(0)7223/9493-0 10 Fax: +49(0)7223/9493-92 11 http://www.addi-data-com 12 info@addi-data.com 13 14This 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. 15 16This 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. 17 18You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 20You shoud also find the complete GPL in the COPYING file accompanying this source code. 21 22@endverbatim 23*/ 24/* 25 26 +-----------------------------------------------------------------------+ 27 | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | 28 +-----------------------------------------------------------------------+ 29 | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | 30 | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | 31 +-------------------------------+---------------------------------------+ 32 | Project : APCI-2032 | Compiler : GCC | 33 | Module name : hwdrv_apci2032.c| Version : 2.96 | 34 +-------------------------------+---------------------------------------+ 35 | Project manager: Eric Stolz | Date : 02/12/2002 | 36 +-------------------------------+---------------------------------------+ 37 | Description : Hardware Layer Acces For APCI-2032 | 38 +-----------------------------------------------------------------------+ 39 | UPDATES | 40 +----------+-----------+------------------------------------------------+ 41 | Date | Author | Description of updates | 42 +----------+-----------+------------------------------------------------+ 43 | | | | 44 | | | | 45 | | | | 46 +----------+-----------+------------------------------------------------+ 47*/ 48 49/* 50+----------------------------------------------------------------------------+ 51| Included files | 52+----------------------------------------------------------------------------+ 53*/ 54 55#include "hwdrv_apci2032.h" 56unsigned int ui_InterruptData, ui_Type; 57/* 58+----------------------------------------------------------------------------+ 59| Function Name : int i_APCI2032_ConfigDigitalOutput | 60| (struct comedi_device *dev,struct comedi_subdevice *s, | 61| struct comedi_insn *insn,unsigned int *data) | 62+----------------------------------------------------------------------------+ 63| Task : Configures The Digital Output Subdevice. | 64+----------------------------------------------------------------------------+ 65| Input Parameters : struct comedi_device *dev : Driver handle | 66| unsigned int *data : Data Pointer contains | 67| configuration parameters as below | 68| | 69| data[1] : 1 Enable VCC Interrupt | 70| 0 Disable VCC Interrupt | 71| data[2] : 1 Enable CC Interrupt | 72| 0 Disable CC Interrupt | 73| | 74+----------------------------------------------------------------------------+ 75| Output Parameters : -- | 76+----------------------------------------------------------------------------+ 77| Return Value : TRUE : No error occur | 78| : FALSE : Error occur. Return the error | 79| | 80+----------------------------------------------------------------------------+ 81*/ 82int i_APCI2032_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, 83 struct comedi_insn *insn, unsigned int *data) 84{ 85 unsigned int ul_Command = 0; 86 devpriv->tsk_Current = current; 87 88 if ((data[0] != 0) && (data[0] != 1)) { 89 comedi_error(dev, 90 "Not a valid Data !!! ,Data should be 1 or 0\n"); 91 return -EINVAL; 92 } /* if ( (data[0]!=0) && (data[0]!=1) ) */ 93 if (data[0]) { 94 devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE; 95 } /* if (data[0]) */ 96 else { 97 devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE; 98 } /* else if (data[0]) */ 99 100 if (data[1] == ADDIDATA_ENABLE) { 101 ul_Command = ul_Command | 0x1; 102 } /* if (data[1] == ADDIDATA_ENABLE) */ 103 else { 104 ul_Command = ul_Command & 0xFFFFFFFE; 105 } /* elseif (data[1] == ADDIDATA_ENABLE) */ 106 if (data[2] == ADDIDATA_ENABLE) { 107 ul_Command = ul_Command | 0x2; 108 } /* if (data[2] == ADDIDATA_ENABLE) */ 109 else { 110 ul_Command = ul_Command & 0xFFFFFFFD; 111 } /* elseif (data[2] == ADDIDATA_ENABLE) */ 112 outl(ul_Command, devpriv->iobase + APCI2032_DIGITAL_OP_INTERRUPT); 113 ui_InterruptData = inl(devpriv->iobase + APCI2032_DIGITAL_OP_INTERRUPT); 114 return insn->n; 115} 116 117/* 118+----------------------------------------------------------------------------+ 119| Function Name : int i_APCI2032_WriteDigitalOutput | 120| (struct comedi_device *dev,struct comedi_subdevice *s, | 121| struct comedi_insn *insn,unsigned int *data) | 122+----------------------------------------------------------------------------+ 123| Task : Writes port value To the selected port | 124+----------------------------------------------------------------------------+ 125| Input Parameters : struct comedi_device *dev : Driver handle | 126| unsigned int ui_NoOfChannels : No Of Channels To Write | 127| unsigned int *data : Data Pointer to read status | 128+----------------------------------------------------------------------------+ 129| Output Parameters : -- | 130+----------------------------------------------------------------------------+ 131| Return Value : TRUE : No error occur | 132| : FALSE : Error occur. Return the error | 133| | 134+----------------------------------------------------------------------------+ 135*/ 136 137int i_APCI2032_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, 138 struct comedi_insn *insn, unsigned int *data) 139{ 140 unsigned int ui_Temp, ui_Temp1; 141 unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ 142 if (devpriv->b_OutputMemoryStatus) { 143 ui_Temp = inl(devpriv->iobase + APCI2032_DIGITAL_OP); 144 145 } /* if(devpriv->b_OutputMemoryStatus ) */ 146 else { 147 ui_Temp = 0; 148 } /* if(devpriv->b_OutputMemoryStatus ) */ 149 if (data[3] == 0) { 150 if (data[1] == 0) { 151 data[0] = (data[0] << ui_NoOfChannel) | ui_Temp; 152 outl(data[0], devpriv->iobase + APCI2032_DIGITAL_OP); 153 } /* if(data[1]==0) */ 154 else { 155 if (data[1] == 1) { 156 switch (ui_NoOfChannel) { 157 158 case 2: 159 data[0] = 160 (data[0] << (2 * 161 data[2])) | ui_Temp; 162 break; 163 164 case 4: 165 data[0] = 166 (data[0] << (4 * 167 data[2])) | ui_Temp; 168 break; 169 170 case 8: 171 data[0] = 172 (data[0] << (8 * 173 data[2])) | ui_Temp; 174 break; 175 176 case 16: 177 data[0] = 178 (data[0] << (16 * 179 data[2])) | ui_Temp; 180 break; 181 case 31: 182 data[0] = data[0] | ui_Temp; 183 break; 184 185 default: 186 comedi_error(dev, " chan spec wrong"); 187 return -EINVAL; /* "sorry channel spec wrong " */ 188 189 } /* switch(ui_NoOfChannels) */ 190 191 outl(data[0], 192 devpriv->iobase + APCI2032_DIGITAL_OP); 193 } /* if(data[1]==1) */ 194 else { 195 printk("\nSpecified channel not supported\n"); 196 } /* else if(data[1]==1) */ 197 } /* elseif(data[1]==0) */ 198 } /* if(data[3]==0) */ 199 else { 200 if (data[3] == 1) { 201 if (data[1] == 0) { 202 data[0] = ~data[0] & 0x1; 203 ui_Temp1 = 1; 204 ui_Temp1 = ui_Temp1 << ui_NoOfChannel; 205 ui_Temp = ui_Temp | ui_Temp1; 206 data[0] = 207 (data[0] << ui_NoOfChannel) ^ 208 0xffffffff; 209 data[0] = data[0] & ui_Temp; 210 outl(data[0], 211 devpriv->iobase + APCI2032_DIGITAL_OP); 212 } /* if(data[1]==0) */ 213 else { 214 if (data[1] == 1) { 215 switch (ui_NoOfChannel) { 216 217 case 2: 218 data[0] = ~data[0] & 0x3; 219 ui_Temp1 = 3; 220 ui_Temp1 = 221 ui_Temp1 << 2 * data[2]; 222 ui_Temp = ui_Temp | ui_Temp1; 223 data[0] = 224 ((data[0] << (2 * 225 data 226 [2])) ^ 227 0xffffffff) & ui_Temp; 228 break; 229 230 case 4: 231 data[0] = ~data[0] & 0xf; 232 ui_Temp1 = 15; 233 ui_Temp1 = 234 ui_Temp1 << 4 * data[2]; 235 ui_Temp = ui_Temp | ui_Temp1; 236 data[0] = 237 ((data[0] << (4 * 238 data 239 [2])) ^ 240 0xffffffff) & ui_Temp; 241 break; 242 243 case 8: 244 data[0] = ~data[0] & 0xff; 245 ui_Temp1 = 255; 246 ui_Temp1 = 247 ui_Temp1 << 8 * data[2]; 248 ui_Temp = ui_Temp | ui_Temp1; 249 data[0] = 250 ((data[0] << (8 * 251 data 252 [2])) ^ 253 0xffffffff) & ui_Temp; 254 break; 255 256 case 16: 257 data[0] = ~data[0] & 0xffff; 258 ui_Temp1 = 65535; 259 ui_Temp1 = 260 ui_Temp1 << 16 * 261 data[2]; 262 ui_Temp = ui_Temp | ui_Temp1; 263 data[0] = 264 ((data[0] << (16 * 265 data 266 [2])) ^ 267 0xffffffff) & ui_Temp; 268 break; 269 270 case 31: 271 break; 272 default: 273 comedi_error(dev, 274 " chan spec wrong"); 275 return -EINVAL; /* "sorry channel spec wrong " */ 276 277 } /* switch(ui_NoOfChannels) */ 278 279 outl(data[0], 280 devpriv->iobase + 281 APCI2032_DIGITAL_OP); 282 } /* if(data[1]==1) */ 283 else { 284 printk("\nSpecified channel not supported\n"); 285 } /* else if(data[1]==1) */ 286 } /* elseif(data[1]==0) */ 287 } /* if(data[3]==1); */ 288 else { 289 printk("\nSpecified functionality does not exist\n"); 290 return -EINVAL; 291 } /* if else data[3]==1) */ 292 } /* if else data[3]==0) */ 293 return (insn->n);; 294} 295 296/* 297+----------------------------------------------------------------------------+ 298| Function Name : int i_APCI2032_ReadDigitalOutput | 299| (struct comedi_device *dev,struct comedi_subdevice *s, | 300| struct comedi_insn *insn,unsigned int *data) | 301+----------------------------------------------------------------------------+ 302| Task : Read value of the selected channel or port | 303+----------------------------------------------------------------------------+ 304| Input Parameters : struct comedi_device *dev : Driver handle | 305| unsigned int ui_NoOfChannels : No Of Channels To read | 306| unsigned int *data : Data Pointer to read status | 307+----------------------------------------------------------------------------+ 308| Output Parameters : -- | 309+----------------------------------------------------------------------------+ 310| Return Value : TRUE : No error occur | 311| : FALSE : Error occur. Return the error | 312| | 313+----------------------------------------------------------------------------+ 314*/ 315 316int i_APCI2032_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, 317 struct comedi_insn *insn, unsigned int *data) 318{ 319 unsigned int ui_Temp; 320 unsigned int ui_NoOfChannel; 321 ui_NoOfChannel = CR_CHAN(insn->chanspec); 322 ui_Temp = data[0]; 323 *data = inl(devpriv->iobase + APCI2032_DIGITAL_OP_RW); 324 if (ui_Temp == 0) { 325 *data = (*data >> ui_NoOfChannel) & 0x1; 326 } /* if (ui_Temp==0) */ 327 else { 328 if (ui_Temp == 1) { 329 switch (ui_NoOfChannel) { 330 331 case 2: 332 *data = (*data >> (2 * data[1])) & 3; 333 break; 334 335 case 4: 336 *data = (*data >> (4 * data[1])) & 15; 337 break; 338 339 case 8: 340 *data = (*data >> (8 * data[1])) & 255; 341 break; 342 343 case 16: 344 *data = (*data >> (16 * data[1])) & 65535; 345 break; 346 347 case 31: 348 break; 349 350 default: 351 comedi_error(dev, " chan spec wrong"); 352 return -EINVAL; /* "sorry channel spec wrong " */ 353 354 } /* switch(ui_NoOfChannels) */ 355 } /* if (ui_Temp==1) */ 356 else { 357 printk("\nSpecified channel not supported \n"); 358 } /* elseif (ui_Temp==1) */ 359 } 360 return insn->n; 361} 362 363/* 364+----------------------------------------------------------------------------+ 365| Function Name : int i_APCI2032_ConfigWatchdog(comedi_device 366| *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)| 367| | 368+----------------------------------------------------------------------------+ 369| Task : Configures The Watchdog | 370+----------------------------------------------------------------------------+ 371| Input Parameters : struct comedi_device *dev : Driver handle | 372| struct comedi_subdevice *s, :pointer to subdevice structure 373| struct comedi_insn *insn :pointer to insn structure | 374| unsigned int *data : Data Pointer to read status | 375+----------------------------------------------------------------------------+ 376| Output Parameters : -- | 377+----------------------------------------------------------------------------+ 378| Return Value : TRUE : No error occur | 379| : FALSE : Error occur. Return the error | 380| | 381+----------------------------------------------------------------------------+ 382*/ 383int i_APCI2032_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, 384 struct comedi_insn *insn, unsigned int *data) 385{ 386 if (data[0] == 0) { 387 /* Disable the watchdog */ 388 outl(0x0, 389 devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + 390 APCI2032_TCW_PROG); 391 /* Loading the Reload value */ 392 outl(data[1], 393 devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + 394 APCI2032_TCW_RELOAD_VALUE); 395 } else { 396 printk("\nThe input parameters are wrong\n"); 397 return -EINVAL; 398 } 399 400 return insn->n; 401} 402 403 /* 404 +----------------------------------------------------------------------------+ 405 | Function Name : int i_APCI2032_StartStopWriteWatchdog | 406 | (struct comedi_device *dev,struct comedi_subdevice *s, 407 struct comedi_insn *insn,unsigned int *data); | 408 +----------------------------------------------------------------------------+ 409 | Task : Start / Stop The Watchdog | 410 +----------------------------------------------------------------------------+ 411 | Input Parameters : struct comedi_device *dev : Driver handle | 412 | struct comedi_subdevice *s, :pointer to subdevice structure 413 struct comedi_insn *insn :pointer to insn structure | 414 | unsigned int *data : Data Pointer to read status | 415 +----------------------------------------------------------------------------+ 416 | Output Parameters : -- | 417 +----------------------------------------------------------------------------+ 418 | Return Value : TRUE : No error occur | 419 | : FALSE : Error occur. Return the error | 420 | | 421 +----------------------------------------------------------------------------+ 422 */ 423 424int i_APCI2032_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, 425 struct comedi_insn *insn, unsigned int *data) 426{ 427 switch (data[0]) { 428 case 0: /* stop the watchdog */ 429 outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_PROG); /* disable the watchdog */ 430 break; 431 case 1: /* start the watchdog */ 432 outl(0x0001, 433 devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + 434 APCI2032_TCW_PROG); 435 break; 436 case 2: /* Software trigger */ 437 outl(0x0201, 438 devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + 439 APCI2032_TCW_PROG); 440 break; 441 default: 442 printk("\nSpecified functionality does not exist\n"); 443 return -EINVAL; 444 } 445 return insn->n; 446} 447 448/* 449+----------------------------------------------------------------------------+ 450| Function Name : int i_APCI2032_ReadWatchdog | 451| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, 452| unsigned int *data); | 453+----------------------------------------------------------------------------+ 454| Task : Read The Watchdog | 455+----------------------------------------------------------------------------+ 456| Input Parameters : struct comedi_device *dev : Driver handle | 457| struct comedi_subdevice *s, :pointer to subdevice structure 458| struct comedi_insn *insn :pointer to insn structure | 459| unsigned int *data : Data Pointer to read status | 460+----------------------------------------------------------------------------+ 461| Output Parameters : -- | 462+----------------------------------------------------------------------------+ 463| Return Value : TRUE : No error occur | 464| : FALSE : Error occur. Return the error | 465| | 466+----------------------------------------------------------------------------+ 467*/ 468 469int i_APCI2032_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, 470 struct comedi_insn *insn, unsigned int *data) 471{ 472 473 data[0] = 474 inl(devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + 475 APCI2032_TCW_TRIG_STATUS) & 0x1; 476 return insn->n; 477} 478 479/* 480+----------------------------------------------------------------------------+ 481| Function Name : void v_APCI2032_Interrupt | 482| (int irq , void *d) | 483+----------------------------------------------------------------------------+ 484| Task : Writes port value To the selected port | 485+----------------------------------------------------------------------------+ 486| Input Parameters : int irq : irq number | 487| void *d : void pointer | 488+----------------------------------------------------------------------------+ 489| Output Parameters : -- | 490+----------------------------------------------------------------------------+ 491| Return Value : TRUE : No error occur | 492| : FALSE : Error occur. Return the error | 493| | 494+----------------------------------------------------------------------------+ 495*/ 496void v_APCI2032_Interrupt(int irq, void *d) 497{ 498 struct comedi_device *dev = d; 499 unsigned int ui_DO; 500 501 ui_DO = inl(devpriv->iobase + APCI2032_DIGITAL_OP_IRQ) & 0x1; /* Check if VCC OR CC interrupt has occured. */ 502 503 if (ui_DO == 0) { 504 printk("\nInterrupt from unKnown source\n"); 505 } /* if(ui_DO==0) */ 506 if (ui_DO) { 507 /* Check for Digital Output interrupt Type - 1: Vcc interrupt 2: CC interrupt. */ 508 ui_Type = 509 inl(devpriv->iobase + 510 APCI2032_DIGITAL_OP_INTERRUPT_STATUS) & 0x3; 511 outl(0x0, 512 devpriv->iobase + APCI2032_DIGITAL_OP + 513 APCI2032_DIGITAL_OP_INTERRUPT); 514 if (ui_Type == 1) { 515 /* Sends signal to user space */ 516 send_sig(SIGIO, devpriv->tsk_Current, 0); 517 } /* if (ui_Type==1) */ 518 else { 519 if (ui_Type == 2) { 520 /* Sends signal to user space */ 521 send_sig(SIGIO, devpriv->tsk_Current, 0); 522 } /* if (ui_Type==2) */ 523 } /* else if (ui_Type==1) */ 524 } /* if(ui_DO) */ 525 526 return; 527 528} 529 530/* 531+----------------------------------------------------------------------------+ 532| Function Name : int i_APCI2032_ReadInterruptStatus | 533| (struct comedi_device *dev,struct comedi_subdevice *s, | 534| struct comedi_insn *insn,unsigned int *data) | 535+----------------------------------------------------------------------------+ 536| Task :Reads the interrupt status register | 537+----------------------------------------------------------------------------+ 538| Input Parameters : | 539+----------------------------------------------------------------------------+ 540| Output Parameters : -- | 541+----------------------------------------------------------------------------+ 542| Return Value : | 543| | 544+----------------------------------------------------------------------------+ 545*/ 546 547int i_APCI2032_ReadInterruptStatus(struct comedi_device *dev, struct comedi_subdevice *s, 548 struct comedi_insn *insn, unsigned int *data) 549{ 550 *data = ui_Type; 551 return insn->n; 552} 553 554/* 555+----------------------------------------------------------------------------+ 556| Function Name : int i_APCI2032_Reset(struct comedi_device *dev) | 557| | 558+----------------------------------------------------------------------------+ 559| Task :Resets the registers of the card | 560+----------------------------------------------------------------------------+ 561| Input Parameters : | 562+----------------------------------------------------------------------------+ 563| Output Parameters : -- | 564+----------------------------------------------------------------------------+ 565| Return Value : | 566| | 567+----------------------------------------------------------------------------+ 568*/ 569 570int i_APCI2032_Reset(struct comedi_device *dev) 571{ 572 devpriv->b_DigitalOutputRegister = 0; 573 ui_Type = 0; 574 outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP); /* Resets the output channels */ 575 outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_INTERRUPT); /* Disables the interrupt. */ 576 outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_PROG); /* disable the watchdog */ 577 outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_RELOAD_VALUE); /* reload=0 */ 578 return 0; 579} 580