cb_pcidio.c revision 790c55415aa31f4c732729f94d2c3a54f7d3bfc2
1/* 2 comedi/drivers/cb_pcidio.c 3 A Comedi driver for PCI-DIO24H & PCI-DIO48H of ComputerBoards (currently MeasurementComputing) 4 5 COMEDI - Linux Control and Measurement Device Interface 6 Copyright (C) 2000 David A. Schleef <ds@schleef.org> 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 22*/ 23/* 24Driver: cb_pcidio 25Description: ComputerBoards' DIO boards with PCI interface 26Devices: [Measurement Computing] PCI-DIO24 (cb_pcidio), PCI-DIO24H, PCI-DIO48H 27Author: Yoshiya Matsuzaka 28Updated: Mon, 29 Oct 2007 15:40:47 +0000 29Status: experimental 30 31This driver has been modified from skel.c of comedi-0.7.70. 32 33Configuration Options: 34 [0] - PCI bus of device (optional) 35 [1] - PCI slot of device (optional) 36 If bus/slot is not specified, the first available PCI device will 37 be used. 38 39Passing a zero for an option is the same as leaving it unspecified. 40*/ 41 42/*------------------------------ HEADER FILES ---------------------------------*/ 43#include "../comedidev.h" 44#include "comedi_pci.h" 45#include "8255.h" 46 47/*-------------------------- MACROS and DATATYPES -----------------------------*/ 48#define PCI_VENDOR_ID_CB 0x1307 49 50/* 51 * Board descriptions for two imaginary boards. Describing the 52 * boards in this way is optional, and completely driver-dependent. 53 * Some drivers use arrays such as this, other do not. 54 */ 55typedef struct pcidio_board_struct { 56 const char *name; // anme of the board 57 int n_8255; // number of 8255 chips on board 58 59 // indices of base address regions 60 int pcicontroler_badrindex; 61 int dioregs_badrindex; 62} pcidio_board; 63 64static const pcidio_board pcidio_boards[] = { 65 { 66 name: "pci-dio24", 67 n_8255: 1, 68 pcicontroler_badrindex:1, 69 dioregs_badrindex:2, 70 }, 71 { 72 name: "pci-dio24h", 73 n_8255: 1, 74 pcicontroler_badrindex:1, 75 dioregs_badrindex:2, 76 }, 77 { 78 name: "pci-dio48h", 79 n_8255: 2, 80 pcicontroler_badrindex:0, 81 dioregs_badrindex:1, 82 }, 83}; 84 85/* This is used by modprobe to translate PCI IDs to drivers. Should 86 * only be used for PCI and ISA-PnP devices */ 87/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded 88 * upstream. */ 89static DEFINE_PCI_DEVICE_TABLE(pcidio_pci_table) = { 90 {PCI_VENDOR_ID_CB, 0x0028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 91 {PCI_VENDOR_ID_CB, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 92 {PCI_VENDOR_ID_CB, 0x000b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 93 {0} 94}; 95 96MODULE_DEVICE_TABLE(pci, pcidio_pci_table); 97 98/* 99 * Useful for shorthand access to the particular board structure 100 */ 101#define thisboard ((const pcidio_board *)dev->board_ptr) 102 103/* this structure is for data unique to this hardware driver. If 104 several hardware drivers keep similar information in this structure, 105 feel free to suggest moving the variable to the comedi_device struct. */ 106typedef struct { 107 int data; // curently unused 108 109 /* would be useful for a PCI device */ 110 struct pci_dev *pci_dev; 111 112 /* used for DO readback, curently unused */ 113 unsigned int do_readback[4]; /* up to 4 unsigned int suffice to hold 96 bits for PCI-DIO96 */ 114 115 unsigned long dio_reg_base; // address of port A of the first 8255 chip on board 116} pcidio_private; 117 118/* 119 * most drivers define the following macro to make it easy to 120 * access the private structure. 121 */ 122#define devpriv ((pcidio_private *)dev->private) 123 124/* 125 * The comedi_driver structure tells the Comedi core module 126 * which functions to call to configure/deconfigure (attach/detach) 127 * the board, and also about the kernel module that contains 128 * the device code. 129 */ 130static int pcidio_attach(comedi_device * dev, comedi_devconfig * it); 131static int pcidio_detach(comedi_device * dev); 132static comedi_driver driver_cb_pcidio = { 133 driver_name:"cb_pcidio", 134 module:THIS_MODULE, 135 attach:pcidio_attach, 136 detach:pcidio_detach, 137/* It is not necessary to implement the following members if you are 138 * writing a driver for a ISA PnP or PCI card */ 139 /* Most drivers will support multiple types of boards by 140 * having an array of board structures. These were defined 141 * in pcidio_boards[] above. Note that the element 'name' 142 * was first in the structure -- Comedi uses this fact to 143 * extract the name of the board without knowing any details 144 * about the structure except for its length. 145 * When a device is attached (by comedi_config), the name 146 * of the device is given to Comedi, and Comedi tries to 147 * match it by going through the list of board names. If 148 * there is a match, the address of the pointer is put 149 * into dev->board_ptr and driver->attach() is called. 150 * 151 * Note that these are not necessary if you can determine 152 * the type of board in software. ISA PnP, PCI, and PCMCIA 153 * devices are such boards. 154 */ 155// The following fields should NOT be initialized if you are dealing with PCI devices 156// board_name: pcidio_boards, 157// offset: sizeof(pcidio_board), 158// num_names: sizeof(pcidio_boards) / sizeof(pcidio_board), 159}; 160 161/*------------------------------- FUNCTIONS -----------------------------------*/ 162 163/* 164 * Attach is called by the Comedi core to configure the driver 165 * for a particular board. If you specified a board_name array 166 * in the driver structure, dev->board_ptr contains that 167 * address. 168 */ 169static int pcidio_attach(comedi_device * dev, comedi_devconfig * it) 170{ 171 struct pci_dev *pcidev = NULL; 172 int index; 173 int i; 174 175 printk("comedi%d: cb_pcidio: \n", dev->minor); 176 177/* 178 * Allocate the private structure area. alloc_private() is a 179 * convenient macro defined in comedidev.h. 180 */ 181 if (alloc_private(dev, sizeof(pcidio_private)) < 0) 182 return -ENOMEM; 183/* 184 * If you can probe the device to determine what device in a series 185 * it is, this is the place to do it. Otherwise, dev->board_ptr 186 * should already be initialized. 187 */ 188/* 189 * Probe the device to determine what device in the series it is. 190 */ 191 192 for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); 193 pcidev != NULL; 194 pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) { 195 // is it not a computer boards card? 196 if (pcidev->vendor != PCI_VENDOR_ID_CB) 197 continue; 198 // loop through cards supported by this driver 199 for (index = 0; 200 index < sizeof pcidio_boards / sizeof(pcidio_board); 201 index++) { 202 if (pcidio_pci_table[index].device != pcidev->device) 203 continue; 204 205 // was a particular bus/slot requested? 206 if (it->options[0] || it->options[1]) { 207 // are we on the wrong bus/slot? 208 if (pcidev->bus->number != it->options[0] || 209 PCI_SLOT(pcidev->devfn) != 210 it->options[1]) { 211 continue; 212 } 213 } 214 dev->board_ptr = pcidio_boards + index; 215 goto found; 216 } 217 } 218 219 printk("No supported ComputerBoards/MeasurementComputing card found on " 220 "requested position\n"); 221 return -EIO; 222 223 found: 224 225/* 226 * Initialize dev->board_name. Note that we can use the "thisboard" 227 * macro now, since we just initialized it in the last line. 228 */ 229 dev->board_name = thisboard->name; 230 231 devpriv->pci_dev = pcidev; 232 printk("Found %s on bus %i, slot %i\n", thisboard->name, 233 devpriv->pci_dev->bus->number, 234 PCI_SLOT(devpriv->pci_dev->devfn)); 235 if (comedi_pci_enable(pcidev, thisboard->name)) { 236 printk("cb_pcidio: failed to enable PCI device and request regions\n"); 237 return -EIO; 238 } 239 devpriv->dio_reg_base 240 = 241 pci_resource_start(devpriv->pci_dev, 242 pcidio_boards[index].dioregs_badrindex); 243 244/* 245 * Allocate the subdevice structures. alloc_subdevice() is a 246 * convenient macro defined in comedidev.h. 247 */ 248 if (alloc_subdevices(dev, thisboard->n_8255) < 0) 249 return -ENOMEM; 250 251 for (i = 0; i < thisboard->n_8255; i++) { 252 subdev_8255_init(dev, dev->subdevices + i, 253 NULL, devpriv->dio_reg_base + i * 4); 254 printk(" subdev %d: base = 0x%lx\n", i, 255 devpriv->dio_reg_base + i * 4); 256 } 257 258 printk("attached\n"); 259 return 1; 260} 261 262/* 263 * _detach is called to deconfigure a device. It should deallocate 264 * resources. 265 * This function is also called when _attach() fails, so it should be 266 * careful not to release resources that were not necessarily 267 * allocated by _attach(). dev->private and dev->subdevices are 268 * deallocated automatically by the core. 269 */ 270static int pcidio_detach(comedi_device * dev) 271{ 272 printk("comedi%d: cb_pcidio: remove\n", dev->minor); 273 if (devpriv) { 274 if (devpriv->pci_dev) { 275 if (devpriv->dio_reg_base) { 276 comedi_pci_disable(devpriv->pci_dev); 277 } 278 pci_dev_put(devpriv->pci_dev); 279 } 280 } 281 if (dev->subdevices) { 282 int i; 283 for (i = 0; i < thisboard->n_8255; i++) { 284 subdev_8255_cleanup(dev, dev->subdevices + i); 285 } 286 } 287 return 0; 288} 289 290/* 291 * A convenient macro that defines init_module() and cleanup_module(), 292 * as necessary. 293 */ 294COMEDI_PCI_INITCLEANUP(driver_cb_pcidio, pcidio_pci_table); 295