adl_pci8164.c revision 6eb78a1bb8a681cd696924fa133c2cb1d7d4deb6
1/* 2 comedi/drivers/adl_pci8164.c 3 4 Hardware comedi driver fot PCI-8164 Adlink card 5 Copyright (C) 2004 Michel Lachine <mike@mikelachaine.ca> 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 21*/ 22/* 23Driver: adl_pci8164 24Description: Driver for the Adlink PCI-8164 4 Axes Motion Control board 25Devices: [ADLink] PCI-8164 (adl_pci8164) 26Author: Michel Lachaine <mike@mikelachaine.ca> 27Status: experimental 28Updated: Mon, 14 Apr 2008 15:10:32 +0100 29 30Configuration Options: 31 [0] - PCI bus of device (optional) 32 [1] - PCI slot of device (optional) 33 If bus/slot is not specified, the first supported 34 PCI device found will be used. 35*/ 36 37#include "../comedidev.h" 38#include <linux/delay.h> 39#include "comedi_fc.h" 40#include "comedi_pci.h" 41#include "8253.h" 42 43#define PCI8164_AXIS_X 0x00 44#define PCI8164_AXIS_Y 0x08 45#define PCI8164_AXIS_Z 0x10 46#define PCI8164_AXIS_U 0x18 47 48#define PCI8164_MSTS 0x00 49#define PCI8164_SSTS 0x02 50#define PCI8164_BUF0 0x04 51#define PCI8164_BUF1 0x06 52 53#define PCI8164_CMD 0x00 54#define PCI8164_OTP 0x02 55 56#define PCI_DEVICE_ID_PCI8164 0x8164 57 58static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = { 59 {PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164, PCI_ANY_ID, PCI_ANY_ID, 0, 60 0, 0}, 61 {0} 62}; 63 64MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table); 65 66typedef struct { 67 int data; 68 struct pci_dev *pci_dev; 69} adl_pci8164_private; 70 71#define devpriv ((adl_pci8164_private *)dev->private) 72 73static int adl_pci8164_attach(comedi_device * dev, comedi_devconfig * it); 74static int adl_pci8164_detach(comedi_device * dev); 75static comedi_driver driver_adl_pci8164 = { 76 driver_name:"adl_pci8164", 77 module:THIS_MODULE, 78 attach:adl_pci8164_attach, 79 detach:adl_pci8164_detach, 80}; 81 82static int adl_pci8164_insn_read_msts(comedi_device * dev, comedi_subdevice * s, 83 comedi_insn * insn, lsampl_t * data); 84 85static int adl_pci8164_insn_read_ssts(comedi_device * dev, comedi_subdevice * s, 86 comedi_insn * insn, lsampl_t * data); 87 88static int adl_pci8164_insn_read_buf0(comedi_device * dev, comedi_subdevice * s, 89 comedi_insn * insn, lsampl_t * data); 90 91static int adl_pci8164_insn_read_buf1(comedi_device * dev, comedi_subdevice * s, 92 comedi_insn * insn, lsampl_t * data); 93 94static int adl_pci8164_insn_write_cmd(comedi_device * dev, comedi_subdevice * s, 95 comedi_insn * insn, lsampl_t * data); 96 97static int adl_pci8164_insn_write_otp(comedi_device * dev, comedi_subdevice * s, 98 comedi_insn * insn, lsampl_t * data); 99 100static int adl_pci8164_insn_write_buf0(comedi_device * dev, 101 comedi_subdevice * s, comedi_insn * insn, lsampl_t * data); 102 103static int adl_pci8164_insn_write_buf1(comedi_device * dev, 104 comedi_subdevice * s, comedi_insn * insn, lsampl_t * data); 105 106static int adl_pci8164_attach(comedi_device * dev, comedi_devconfig * it) 107{ 108 struct pci_dev *pcidev; 109 comedi_subdevice *s; 110 int bus, slot; 111 112 printk("comedi: attempt to attach...\n"); 113 printk("comedi%d: adl_pci8164\n", dev->minor); 114 115 dev->board_name = "pci8164"; 116 bus = it->options[0]; 117 slot = it->options[1]; 118 119 if (alloc_private(dev, sizeof(adl_pci8164_private)) < 0) 120 return -ENOMEM; 121 122 if (alloc_subdevices(dev, 4) < 0) 123 return -ENOMEM; 124 125 for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); 126 pcidev != NULL; 127 pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) { 128 129 if (pcidev->vendor == PCI_VENDOR_ID_ADLINK && 130 pcidev->device == PCI_DEVICE_ID_PCI8164) { 131 if (bus || slot) { 132 /* requested particular bus/slot */ 133 if (pcidev->bus->number != bus 134 || PCI_SLOT(pcidev->devfn) != slot) { 135 continue; 136 } 137 } 138 devpriv->pci_dev = pcidev; 139 if (comedi_pci_enable(pcidev, "adl_pci8164") < 0) { 140 printk("comedi%d: Failed to enable PCI device and request regions\n", dev->minor); 141 return -EIO; 142 } 143 dev->iobase = pci_resource_start(pcidev, 2); 144 printk("comedi: base addr %4lx\n", dev->iobase); 145 146 s = dev->subdevices + 0; 147 s->type = COMEDI_SUBD_PROC; 148 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 149 s->n_chan = 4; 150 s->maxdata = 0xffff; 151 s->len_chanlist = 4; 152 //s->range_table = &range_axis; 153 s->insn_read = adl_pci8164_insn_read_msts; 154 s->insn_write = adl_pci8164_insn_write_cmd; 155 156 s = dev->subdevices + 1; 157 s->type = COMEDI_SUBD_PROC; 158 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 159 s->n_chan = 4; 160 s->maxdata = 0xffff; 161 s->len_chanlist = 4; 162 //s->range_table = &range_axis; 163 s->insn_read = adl_pci8164_insn_read_ssts; 164 s->insn_write = adl_pci8164_insn_write_otp; 165 166 s = dev->subdevices + 2; 167 s->type = COMEDI_SUBD_PROC; 168 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 169 s->n_chan = 4; 170 s->maxdata = 0xffff; 171 s->len_chanlist = 4; 172 //s->range_table = &range_axis; 173 s->insn_read = adl_pci8164_insn_read_buf0; 174 s->insn_write = adl_pci8164_insn_write_buf0; 175 176 s = dev->subdevices + 3; 177 s->type = COMEDI_SUBD_PROC; 178 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 179 s->n_chan = 4; 180 s->maxdata = 0xffff; 181 s->len_chanlist = 4; 182 //s->range_table = &range_axis; 183 s->insn_read = adl_pci8164_insn_read_buf1; 184 s->insn_write = adl_pci8164_insn_write_buf1; 185 186 printk("comedi: attached\n"); 187 188 return 1; 189 } 190 } 191 192 printk("comedi%d: no supported board found! (req. bus/slot : %d/%d)\n", 193 dev->minor, bus, slot); 194 return -EIO; 195} 196 197static int adl_pci8164_detach(comedi_device * dev) 198{ 199 printk("comedi%d: pci8164: remove\n", dev->minor); 200 201 if (devpriv && devpriv->pci_dev) { 202 if (dev->iobase) { 203 comedi_pci_disable(devpriv->pci_dev); 204 } 205 pci_dev_put(devpriv->pci_dev); 206 } 207 208 return 0; 209} 210 211static int adl_pci8164_insn_read_msts(comedi_device * dev, comedi_subdevice * s, 212 comedi_insn * insn, lsampl_t * data) 213{ 214 int axis, axis_reg; 215 char *axisname; 216 217 axis = CR_CHAN(insn->chanspec); 218 219 switch (axis) { 220 case 0: 221 axis_reg = PCI8164_AXIS_X; 222 axisname = "X"; 223 break; 224 case 1: 225 axis_reg = PCI8164_AXIS_Y; 226 axisname = "Y"; 227 break; 228 case 2: 229 axis_reg = PCI8164_AXIS_Z; 230 axisname = "Z"; 231 break; 232 case 3: 233 axis_reg = PCI8164_AXIS_U; 234 axisname = "U"; 235 break; 236 default: 237 axis_reg = PCI8164_AXIS_X; 238 axisname = "X"; 239 } 240 241 data[0] = inw(dev->iobase + axis_reg + PCI8164_MSTS); 242 printk("comedi: pci8164 MSTS read -> %04X:%04X on axis %s\n", data[0], 243 data[1], axisname); 244 245 return 2; 246} 247 248static int adl_pci8164_insn_read_ssts(comedi_device * dev, comedi_subdevice * s, 249 comedi_insn * insn, lsampl_t * data) 250{ 251 int axis, axis_reg; 252 char *axisname; 253 254 axis = CR_CHAN(insn->chanspec); 255 256 switch (axis) { 257 case 0: 258 axis_reg = PCI8164_AXIS_X; 259 axisname = "X"; 260 break; 261 case 1: 262 axis_reg = PCI8164_AXIS_Y; 263 axisname = "Y"; 264 break; 265 case 2: 266 axis_reg = PCI8164_AXIS_Z; 267 axisname = "Z"; 268 break; 269 case 3: 270 axis_reg = PCI8164_AXIS_U; 271 axisname = "U"; 272 break; 273 default: 274 axis_reg = PCI8164_AXIS_X; 275 axisname = "X"; 276 } 277 278 data[0] = inw(dev->iobase + axis_reg + PCI8164_SSTS); 279 printk("comedi: pci8164 SSTS read -> %04X:%04X on axis %s\n", data[0], 280 data[1], axisname); 281 282 return 2; 283} 284 285static int adl_pci8164_insn_read_buf0(comedi_device * dev, comedi_subdevice * s, 286 comedi_insn * insn, lsampl_t * data) 287{ 288 int axis, axis_reg; 289 char *axisname; 290 291 axis = CR_CHAN(insn->chanspec); 292 293 switch (axis) { 294 case 0: 295 axis_reg = PCI8164_AXIS_X; 296 axisname = "X"; 297 break; 298 case 1: 299 axis_reg = PCI8164_AXIS_Y; 300 axisname = "Y"; 301 break; 302 case 2: 303 axis_reg = PCI8164_AXIS_Z; 304 axisname = "Z"; 305 break; 306 case 3: 307 axis_reg = PCI8164_AXIS_U; 308 axisname = "U"; 309 break; 310 default: 311 axis_reg = PCI8164_AXIS_X; 312 axisname = "X"; 313 } 314 315 data[0] = inw(dev->iobase + axis_reg + PCI8164_BUF0); 316 printk("comedi: pci8164 BUF0 read -> %04X:%04X on axis %s\n", data[0], 317 data[1], axisname); 318 319 return 2; 320} 321 322static int adl_pci8164_insn_read_buf1(comedi_device * dev, comedi_subdevice * s, 323 comedi_insn * insn, lsampl_t * data) 324{ 325 int axis, axis_reg; 326 327 char *axisname; 328 329 axis = CR_CHAN(insn->chanspec); 330 331 switch (axis) { 332 case 0: 333 axis_reg = PCI8164_AXIS_X; 334 axisname = "X"; 335 break; 336 case 1: 337 axis_reg = PCI8164_AXIS_Y; 338 axisname = "Y"; 339 break; 340 case 2: 341 axis_reg = PCI8164_AXIS_Z; 342 axisname = "Z"; 343 break; 344 case 3: 345 axis_reg = PCI8164_AXIS_U; 346 axisname = "U"; 347 break; 348 default: 349 axis_reg = PCI8164_AXIS_X; 350 axisname = "X"; 351 } 352 353 data[0] = inw(dev->iobase + axis_reg + PCI8164_BUF1); 354 printk("comedi: pci8164 BUF1 read -> %04X:%04X on axis %s\n", data[0], 355 data[1], axisname); 356 357 return 2; 358} 359 360static int adl_pci8164_insn_write_cmd(comedi_device * dev, comedi_subdevice * s, 361 comedi_insn * insn, lsampl_t * data) 362{ 363 unsigned int axis, axis_reg; 364 365 char *axisname; 366 367 axis = CR_CHAN(insn->chanspec); 368 369 switch (axis) { 370 case 0: 371 axis_reg = PCI8164_AXIS_X; 372 axisname = "X"; 373 break; 374 case 1: 375 axis_reg = PCI8164_AXIS_Y; 376 axisname = "Y"; 377 break; 378 case 2: 379 axis_reg = PCI8164_AXIS_Z; 380 axisname = "Z"; 381 break; 382 case 3: 383 axis_reg = PCI8164_AXIS_U; 384 axisname = "U"; 385 break; 386 default: 387 axis_reg = PCI8164_AXIS_X; 388 axisname = "X"; 389 } 390 391 outw(data[0], dev->iobase + axis_reg + PCI8164_CMD); 392 printk("comedi: pci8164 CMD write -> %04X:%04X on axis %s\n", data[0], 393 data[1], axisname); 394 395 return 2; 396} 397 398static int adl_pci8164_insn_write_otp(comedi_device * dev, comedi_subdevice * s, 399 comedi_insn * insn, lsampl_t * data) 400{ 401 int axis, axis_reg; 402 403 char *axisname; 404 405 axis = CR_CHAN(insn->chanspec); 406 407 switch (axis) { 408 case 0: 409 axis_reg = PCI8164_AXIS_X; 410 axisname = "X"; 411 break; 412 case 1: 413 axis_reg = PCI8164_AXIS_Y; 414 axisname = "Y"; 415 break; 416 case 2: 417 axis_reg = PCI8164_AXIS_Z; 418 axisname = "Z"; 419 break; 420 case 3: 421 axis_reg = PCI8164_AXIS_U; 422 axisname = "U"; 423 break; 424 default: 425 axis_reg = PCI8164_AXIS_X; 426 axisname = "X"; 427 } 428 429 outw(data[0], dev->iobase + axis_reg + PCI8164_OTP); 430 printk("comedi: pci8164 OTP write -> %04X:%04X on axis %s\n", data[0], 431 data[1], axisname); 432 433 return 2; 434} 435 436static int adl_pci8164_insn_write_buf0(comedi_device * dev, 437 comedi_subdevice * s, comedi_insn * insn, lsampl_t * data) 438{ 439 int axis, axis_reg; 440 441 char *axisname; 442 443 axis = CR_CHAN(insn->chanspec); 444 445 switch (axis) { 446 case 0: 447 axis_reg = PCI8164_AXIS_X; 448 axisname = "X"; 449 break; 450 case 1: 451 axis_reg = PCI8164_AXIS_Y; 452 axisname = "Y"; 453 break; 454 case 2: 455 axis_reg = PCI8164_AXIS_Z; 456 axisname = "Z"; 457 break; 458 case 3: 459 axis_reg = PCI8164_AXIS_U; 460 axisname = "U"; 461 break; 462 default: 463 axis_reg = PCI8164_AXIS_X; 464 axisname = "X"; 465 } 466 467 outw(data[0], dev->iobase + axis_reg + PCI8164_BUF0); 468 printk("comedi: pci8164 BUF0 write -> %04X:%04X on axis %s\n", data[0], 469 data[1], axisname); 470 471 return 2; 472} 473 474static int adl_pci8164_insn_write_buf1(comedi_device * dev, 475 comedi_subdevice * s, comedi_insn * insn, lsampl_t * data) 476{ 477 int axis, axis_reg; 478 479 char *axisname; 480 481 axis = CR_CHAN(insn->chanspec); 482 483 switch (axis) { 484 case 0: 485 axis_reg = PCI8164_AXIS_X; 486 axisname = "X"; 487 break; 488 case 1: 489 axis_reg = PCI8164_AXIS_Y; 490 axisname = "Y"; 491 break; 492 case 2: 493 axis_reg = PCI8164_AXIS_Z; 494 axisname = "Z"; 495 break; 496 case 3: 497 axis_reg = PCI8164_AXIS_U; 498 axisname = "U"; 499 break; 500 default: 501 axis_reg = PCI8164_AXIS_X; 502 axisname = "X"; 503 } 504 505 outw(data[0], dev->iobase + axis_reg + PCI8164_BUF1); 506 printk("comedi: pci8164 BUF1 write -> %04X:%04X on axis %s\n", data[0], 507 data[1], axisname); 508 509 return 2; 510} 511 512COMEDI_PCI_INITCLEANUP(driver_adl_pci8164, adl_pci8164_pci_table); 513