-
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.
Staging: comedi: add cb_pcidio driver
Driver for PCI-DIO24H & PCI-DIO48H of ComputerBoards (currently MeasurementComputing) From: Yoshiya Matsuzaka <matsuzay@mail.cc.tohoku.ac.jp> Cc: David Schleef <ds@schleef.org> Cc: Ian Abbott <abbotti@mev.co.uk> Cc: Frank Mori Hess <fmhess@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
- Loading branch information
Yoshiya Matsuzaka
authored and
Greg Kroah-Hartman
committed
Apr 3, 2009
1 parent
2c89e15
commit 028d486
Showing
1 changed file
with
294 additions
and
0 deletions.
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 |
---|---|---|
@@ -0,0 +1,294 @@ | ||
/* | ||
comedi/drivers/cb_pcidio.c | ||
A Comedi driver for PCI-DIO24H & PCI-DIO48H of ComputerBoards (currently MeasurementComputing) | ||
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: cb_pcidio | ||
Description: ComputerBoards' DIO boards with PCI interface | ||
Devices: [Measurement Computing] PCI-DIO24 (cb_pcidio), PCI-DIO24H, PCI-DIO48H | ||
Author: Yoshiya Matsuzaka | ||
Updated: Mon, 29 Oct 2007 15:40:47 +0000 | ||
Status: experimental | ||
This driver has been modified from skel.c of comedi-0.7.70. | ||
Configuration Options: | ||
[0] - PCI bus of device (optional) | ||
[1] - PCI slot of device (optional) | ||
If bus/slot is not specified, the first available PCI device will | ||
be used. | ||
Passing a zero for an option is the same as leaving it unspecified. | ||
*/ | ||
|
||
/*------------------------------ HEADER FILES ---------------------------------*/ | ||
#include "../comedidev.h" | ||
#include "comedi_pci.h" | ||
#include "8255.h" | ||
|
||
/*-------------------------- MACROS and DATATYPES -----------------------------*/ | ||
#define PCI_VENDOR_ID_CB 0x1307 | ||
|
||
/* | ||
* Board descriptions for two imaginary boards. Describing the | ||
* boards in this way is optional, and completely driver-dependent. | ||
* Some drivers use arrays such as this, other do not. | ||
*/ | ||
typedef struct pcidio_board_struct { | ||
const char *name; // anme of the board | ||
int n_8255; // number of 8255 chips on board | ||
|
||
// indices of base address regions | ||
int pcicontroler_badrindex; | ||
int dioregs_badrindex; | ||
} pcidio_board; | ||
|
||
static const pcidio_board pcidio_boards[] = { | ||
{ | ||
name: "pci-dio24", | ||
n_8255: 1, | ||
pcicontroler_badrindex:1, | ||
dioregs_badrindex:2, | ||
}, | ||
{ | ||
name: "pci-dio24h", | ||
n_8255: 1, | ||
pcicontroler_badrindex:1, | ||
dioregs_badrindex:2, | ||
}, | ||
{ | ||
name: "pci-dio48h", | ||
n_8255: 2, | ||
pcicontroler_badrindex:0, | ||
dioregs_badrindex:1, | ||
}, | ||
}; | ||
|
||
/* This is used by modprobe to translate PCI IDs to drivers. Should | ||
* only be used for PCI and ISA-PnP devices */ | ||
/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded | ||
* upstream. */ | ||
static DEFINE_PCI_DEVICE_TABLE(pcidio_pci_table) = { | ||
{PCI_VENDOR_ID_CB, 0x0028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
{PCI_VENDOR_ID_CB, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
{PCI_VENDOR_ID_CB, 0x000b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
{0} | ||
}; | ||
|
||
MODULE_DEVICE_TABLE(pci, pcidio_pci_table); | ||
|
||
/* | ||
* Useful for shorthand access to the particular board structure | ||
*/ | ||
#define thisboard ((const pcidio_board *)dev->board_ptr) | ||
|
||
/* this structure is for data unique to this hardware driver. If | ||
several hardware drivers keep similar information in this structure, | ||
feel free to suggest moving the variable to the comedi_device struct. */ | ||
typedef struct { | ||
int data; // curently unused | ||
|
||
/* would be useful for a PCI device */ | ||
struct pci_dev *pci_dev; | ||
|
||
/* used for DO readback, curently unused */ | ||
lsampl_t do_readback[4]; /* up to 4 lsampl_t suffice to hold 96 bits for PCI-DIO96 */ | ||
|
||
unsigned long dio_reg_base; // address of port A of the first 8255 chip on board | ||
} pcidio_private; | ||
|
||
/* | ||
* most drivers define the following macro to make it easy to | ||
* access the private structure. | ||
*/ | ||
#define devpriv ((pcidio_private *)dev->private) | ||
|
||
/* | ||
* The comedi_driver structure tells the Comedi core module | ||
* which functions to call to configure/deconfigure (attach/detach) | ||
* the board, and also about the kernel module that contains | ||
* the device code. | ||
*/ | ||
static int pcidio_attach(comedi_device * dev, comedi_devconfig * it); | ||
static int pcidio_detach(comedi_device * dev); | ||
static comedi_driver driver_cb_pcidio = { | ||
driver_name:"cb_pcidio", | ||
module:THIS_MODULE, | ||
attach:pcidio_attach, | ||
detach:pcidio_detach, | ||
/* It is not necessary to implement the following members if you are | ||
* writing a driver for a ISA PnP or PCI card */ | ||
/* Most drivers will support multiple types of boards by | ||
* having an array of board structures. These were defined | ||
* in pcidio_boards[] above. Note that the element 'name' | ||
* was first in the structure -- Comedi uses this fact to | ||
* extract the name of the board without knowing any details | ||
* about the structure except for its length. | ||
* When a device is attached (by comedi_config), the name | ||
* of the device is given to Comedi, and Comedi tries to | ||
* match it by going through the list of board names. If | ||
* there is a match, the address of the pointer is put | ||
* into dev->board_ptr and driver->attach() is called. | ||
* | ||
* Note that these are not necessary if you can determine | ||
* the type of board in software. ISA PnP, PCI, and PCMCIA | ||
* devices are such boards. | ||
*/ | ||
// The following fields should NOT be initialized if you are dealing with PCI devices | ||
// board_name: pcidio_boards, | ||
// offset: sizeof(pcidio_board), | ||
// num_names: sizeof(pcidio_boards) / sizeof(pcidio_board), | ||
}; | ||
|
||
/*------------------------------- FUNCTIONS -----------------------------------*/ | ||
|
||
/* | ||
* Attach is called by the Comedi core to configure the driver | ||
* for a particular board. If you specified a board_name array | ||
* in the driver structure, dev->board_ptr contains that | ||
* address. | ||
*/ | ||
static int pcidio_attach(comedi_device * dev, comedi_devconfig * it) | ||
{ | ||
struct pci_dev *pcidev = NULL; | ||
int index; | ||
int i; | ||
|
||
printk("comedi%d: cb_pcidio: \n", dev->minor); | ||
|
||
/* | ||
* Allocate the private structure area. alloc_private() is a | ||
* convenient macro defined in comedidev.h. | ||
*/ | ||
if (alloc_private(dev, sizeof(pcidio_private)) < 0) | ||
return -ENOMEM; | ||
/* | ||
* If you can probe the device to determine what device in a series | ||
* it is, this is the place to do it. Otherwise, dev->board_ptr | ||
* should already be initialized. | ||
*/ | ||
/* | ||
* Probe the device to determine what device in the series it is. | ||
*/ | ||
|
||
for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); | ||
pcidev != NULL; | ||
pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) { | ||
// is it not a computer boards card? | ||
if (pcidev->vendor != PCI_VENDOR_ID_CB) | ||
continue; | ||
// loop through cards supported by this driver | ||
for (index = 0; | ||
index < sizeof pcidio_boards / sizeof(pcidio_board); | ||
index++) { | ||
if (pcidio_pci_table[index].device != pcidev->device) | ||
continue; | ||
|
||
// was a particular bus/slot requested? | ||
if (it->options[0] || it->options[1]) { | ||
// are we on the wrong bus/slot? | ||
if (pcidev->bus->number != it->options[0] || | ||
PCI_SLOT(pcidev->devfn) != | ||
it->options[1]) { | ||
continue; | ||
} | ||
} | ||
dev->board_ptr = pcidio_boards + index; | ||
goto found; | ||
} | ||
} | ||
|
||
printk("No supported ComputerBoards/MeasurementComputing card found on " | ||
"requested position\n"); | ||
return -EIO; | ||
|
||
found: | ||
|
||
/* | ||
* Initialize dev->board_name. Note that we can use the "thisboard" | ||
* macro now, since we just initialized it in the last line. | ||
*/ | ||
dev->board_name = thisboard->name; | ||
|
||
devpriv->pci_dev = pcidev; | ||
printk("Found %s on bus %i, slot %i\n", thisboard->name, | ||
devpriv->pci_dev->bus->number, | ||
PCI_SLOT(devpriv->pci_dev->devfn)); | ||
if (comedi_pci_enable(pcidev, thisboard->name)) { | ||
printk("cb_pcidio: failed to enable PCI device and request regions\n"); | ||
return -EIO; | ||
} | ||
devpriv->dio_reg_base | ||
= | ||
pci_resource_start(devpriv->pci_dev, | ||
pcidio_boards[index].dioregs_badrindex); | ||
|
||
/* | ||
* Allocate the subdevice structures. alloc_subdevice() is a | ||
* convenient macro defined in comedidev.h. | ||
*/ | ||
if (alloc_subdevices(dev, thisboard->n_8255) < 0) | ||
return -ENOMEM; | ||
|
||
for (i = 0; i < thisboard->n_8255; i++) { | ||
subdev_8255_init(dev, dev->subdevices + i, | ||
NULL, devpriv->dio_reg_base + i * 4); | ||
printk(" subdev %d: base = 0x%lx\n", i, | ||
devpriv->dio_reg_base + i * 4); | ||
} | ||
|
||
printk("attached\n"); | ||
return 1; | ||
} | ||
|
||
/* | ||
* _detach is called to deconfigure a device. It should deallocate | ||
* resources. | ||
* This function is also called when _attach() fails, so it should be | ||
* careful not to release resources that were not necessarily | ||
* allocated by _attach(). dev->private and dev->subdevices are | ||
* deallocated automatically by the core. | ||
*/ | ||
static int pcidio_detach(comedi_device * dev) | ||
{ | ||
printk("comedi%d: cb_pcidio: remove\n", dev->minor); | ||
if (devpriv) { | ||
if (devpriv->pci_dev) { | ||
if (devpriv->dio_reg_base) { | ||
comedi_pci_disable(devpriv->pci_dev); | ||
} | ||
pci_dev_put(devpriv->pci_dev); | ||
} | ||
} | ||
if (dev->subdevices) { | ||
int i; | ||
for (i = 0; i < thisboard->n_8255; i++) { | ||
subdev_8255_cleanup(dev, dev->subdevices + i); | ||
} | ||
} | ||
return 0; | ||
} | ||
|
||
/* | ||
* A convenient macro that defines init_module() and cleanup_module(), | ||
* as necessary. | ||
*/ | ||
COMEDI_PCI_INITCLEANUP(driver_cb_pcidio, pcidio_pci_table); |