-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 141395 b: refs/heads/master c: 2f82613 h: refs/heads/master i: 141393: 792edd5 141391: 7e17637 v: v3
- Loading branch information
Michael Hillmann
authored and
Greg Kroah-Hartman
committed
Apr 3, 2009
1 parent
9e73791
commit d58089c
Showing
2 changed files
with
251 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: eb3a3c1b7c92a129f43541c6ceb0e277fc61e354 | ||
refs/heads/master: 2f82613d3a7ef447be4ce656f757fc1ea101a4f1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
/* | ||
comedi/drivers/ke_counter.c | ||
Comedi driver for Kolter-Electronic PCI Counter 1 Card | ||
COMEDI - Linux Control and Measurement Device Interface | ||
Copyright (C) 2000 David A. Schleef <ds@schleef.org> | ||
This 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. | ||
This 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. | ||
You should have received a copy of the GNU General Public License | ||
along with this program; if not, write to the Free Software | ||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
*/ | ||
/* | ||
Driver: ke_counter | ||
Description: Driver for Kolter Electronic Counter Card | ||
Devices: [Kolter Electronic] PCI Counter Card (ke_counter) | ||
Author: Michael Hillmann | ||
Updated: Mon, 14 Apr 2008 15:42:42 +0100 | ||
Status: tested | ||
Configuration Options: | ||
[0] - PCI bus of device (optional) | ||
[1] - PCI slot of device (optional) | ||
If bus/slot is not specified, the first supported | ||
PCI device found will be used. | ||
This driver is a simple driver to read the counter values from | ||
Kolter Electronic PCI Counter Card. | ||
*/ | ||
|
||
#include "../comedidev.h" | ||
|
||
#include "comedi_pci.h" | ||
|
||
#define CNT_DRIVER_NAME "ke_counter" | ||
#define PCI_VENDOR_ID_KOLTER 0x1001 | ||
#define CNT_CARD_DEVICE_ID 0x0014 | ||
|
||
/*-- function prototypes ----------------------------------------------------*/ | ||
|
||
static int cnt_attach(comedi_device * dev, comedi_devconfig * it); | ||
static int cnt_detach(comedi_device * dev); | ||
|
||
static DEFINE_PCI_DEVICE_TABLE(cnt_pci_table) = { | ||
{PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, | ||
0}, | ||
{0} | ||
}; | ||
|
||
MODULE_DEVICE_TABLE(pci, cnt_pci_table); | ||
|
||
/*-- board specification structure ------------------------------------------*/ | ||
|
||
typedef struct { | ||
const char *name; | ||
int device_id; | ||
int cnt_channel_nbr; | ||
int cnt_bits; | ||
} cnt_board_struct; | ||
|
||
static const cnt_board_struct cnt_boards[] = { | ||
{ | ||
name: CNT_DRIVER_NAME, | ||
device_id:CNT_CARD_DEVICE_ID, | ||
cnt_channel_nbr:3, | ||
cnt_bits:24} | ||
}; | ||
|
||
#define cnt_board_nbr (sizeof(cnt_boards)/sizeof(cnt_board_struct)) | ||
|
||
/*-- device private structure -----------------------------------------------*/ | ||
|
||
typedef struct { | ||
struct pci_dev *pcidev; | ||
} cnt_device_private; | ||
|
||
#define devpriv ((cnt_device_private *)dev->private) | ||
|
||
static comedi_driver cnt_driver = { | ||
driver_name:CNT_DRIVER_NAME, | ||
module:THIS_MODULE, | ||
attach:cnt_attach, | ||
detach:cnt_detach, | ||
}; | ||
|
||
COMEDI_PCI_INITCLEANUP(cnt_driver, cnt_pci_table); | ||
|
||
/*-- counter write ----------------------------------------------------------*/ | ||
|
||
/* This should be used only for resetting the counters; maybe it is better | ||
to make a special command 'reset'. */ | ||
static int cnt_winsn(comedi_device * dev, | ||
comedi_subdevice * s, comedi_insn * insn, lsampl_t * data) | ||
{ | ||
int chan = CR_CHAN(insn->chanspec); | ||
|
||
outb((unsigned char)((data[0] >> 24) & 0xff), | ||
dev->iobase + chan * 0x20 + 0x10); | ||
outb((unsigned char)((data[0] >> 16) & 0xff), | ||
dev->iobase + chan * 0x20 + 0x0c); | ||
outb((unsigned char)((data[0] >> 8) & 0xff), | ||
dev->iobase + chan * 0x20 + 0x08); | ||
outb((unsigned char)((data[0] >> 0) & 0xff), | ||
dev->iobase + chan * 0x20 + 0x04); | ||
|
||
/* return the number of samples written */ | ||
return 1; | ||
} | ||
|
||
/*-- counter read -----------------------------------------------------------*/ | ||
|
||
static int cnt_rinsn(comedi_device * dev, | ||
comedi_subdevice * s, comedi_insn * insn, lsampl_t * data) | ||
{ | ||
unsigned char a0, a1, a2, a3, a4; | ||
int chan = CR_CHAN(insn->chanspec); | ||
int result; | ||
|
||
a0 = inb(dev->iobase + chan * 0x20); | ||
a1 = inb(dev->iobase + chan * 0x20 + 0x04); | ||
a2 = inb(dev->iobase + chan * 0x20 + 0x08); | ||
a3 = inb(dev->iobase + chan * 0x20 + 0x0c); | ||
a4 = inb(dev->iobase + chan * 0x20 + 0x10); | ||
|
||
result = (a1 + (a2 * 256) + (a3 * 65536)); | ||
if (a4 > 0) | ||
result = result - s->maxdata; | ||
|
||
*data = (lsampl_t) result; | ||
|
||
/* return the number of samples read */ | ||
return 1; | ||
} | ||
|
||
/*-- attach -----------------------------------------------------------------*/ | ||
|
||
static int cnt_attach(comedi_device * dev, comedi_devconfig * it) | ||
{ | ||
comedi_subdevice *subdevice; | ||
struct pci_dev *pci_device; | ||
cnt_board_struct *board; | ||
unsigned long io_base; | ||
int error, i; | ||
|
||
/* allocate device private structure */ | ||
if ((error = alloc_private(dev, sizeof(cnt_device_private))) < 0) { | ||
return error; | ||
} | ||
|
||
/* Probe the device to determine what device in the series it is. */ | ||
for (pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); | ||
pci_device != NULL; | ||
pci_device = | ||
pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_device)) { | ||
if (pci_device->vendor == PCI_VENDOR_ID_KOLTER) { | ||
for (i = 0; i < cnt_board_nbr; i++) { | ||
if (cnt_boards[i].device_id == | ||
pci_device->device) { | ||
/* was a particular bus/slot requested? */ | ||
if ((it->options[0] != 0) | ||
|| (it->options[1] != 0)) { | ||
/* are we on the wrong bus/slot? */ | ||
if (pci_device->bus->number != | ||
it->options[0] | ||
|| PCI_SLOT(pci_device-> | ||
devfn) != | ||
it->options[1]) { | ||
continue; | ||
} | ||
} | ||
|
||
dev->board_ptr = cnt_boards + i; | ||
board = (cnt_board_struct *) dev-> | ||
board_ptr; | ||
goto found; | ||
} | ||
} | ||
} | ||
} | ||
printk("comedi%d: no supported board found! (req. bus/slot: %d/%d)\n", | ||
dev->minor, it->options[0], it->options[1]); | ||
return -EIO; | ||
|
||
found: | ||
printk("comedi%d: found %s at PCI bus %d, slot %d\n", dev->minor, | ||
board->name, pci_device->bus->number, | ||
PCI_SLOT(pci_device->devfn)); | ||
devpriv->pcidev = pci_device; | ||
dev->board_name = board->name; | ||
|
||
/* enable PCI device and request regions */ | ||
if ((error = comedi_pci_enable(pci_device, CNT_DRIVER_NAME)) < 0) { | ||
printk("comedi%d: failed to enable PCI device and request regions!\n", dev->minor); | ||
return error; | ||
} | ||
|
||
/* read register base address [PCI_BASE_ADDRESS #0] */ | ||
io_base = pci_resource_start(pci_device, 0); | ||
dev->iobase = io_base; | ||
|
||
/* allocate the subdevice structures */ | ||
if ((error = alloc_subdevices(dev, 1)) < 0) { | ||
return error; | ||
} | ||
|
||
subdevice = dev->subdevices + 0; | ||
dev->read_subdev = subdevice; | ||
|
||
subdevice->type = COMEDI_SUBD_COUNTER; | ||
subdevice->subdev_flags = SDF_READABLE /* | SDF_COMMON */ ; | ||
subdevice->n_chan = board->cnt_channel_nbr; | ||
subdevice->maxdata = (1 << board->cnt_bits) - 1; | ||
subdevice->insn_read = cnt_rinsn; | ||
subdevice->insn_write = cnt_winsn; | ||
|
||
// select 20MHz clock | ||
outb(3, dev->iobase + 248); | ||
|
||
// reset all counters | ||
outb(0, dev->iobase); | ||
outb(0, dev->iobase + 0x20); | ||
outb(0, dev->iobase + 0x40); | ||
|
||
printk("comedi%d: " CNT_DRIVER_NAME " attached.\n", dev->minor); | ||
return 0; | ||
} | ||
|
||
/*-- detach -----------------------------------------------------------------*/ | ||
|
||
static int cnt_detach(comedi_device * dev) | ||
{ | ||
if (devpriv && devpriv->pcidev) { | ||
if (dev->iobase) { | ||
comedi_pci_disable(devpriv->pcidev); | ||
} | ||
pci_dev_put(devpriv->pcidev); | ||
} | ||
printk("comedi%d: " CNT_DRIVER_NAME " remove\n", dev->minor); | ||
return 0; | ||
} |