skel.c revision fc6a12e5076255c7d0160a6e3749b89c7e4b5beb
1fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 2fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef comedi/drivers/skel.c 3fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef Skeleton code for a Comedi driver 4fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 5fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef COMEDI - Linux Control and Measurement Device Interface 6fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef Copyright (C) 2000 David A. Schleef <ds@schleef.org> 7fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 8fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef This program is free software; you can redistribute it and/or modify 9fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef it under the terms of the GNU General Public License as published by 10fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef the Free Software Foundation; either version 2 of the License, or 11fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef (at your option) any later version. 12fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 13fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef This program is distributed in the hope that it will be useful, 14fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef but WITHOUT ANY WARRANTY; without even the implied warranty of 15fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef GNU General Public License for more details. 17fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 18fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef You should have received a copy of the GNU General Public License 19fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef along with this program; if not, write to the Free Software 20fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 22fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef*/ 23fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 24fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid SchleefDriver: skel 25fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid SchleefDescription: Skeleton driver, an example for driver writers 26fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid SchleefDevices: 27fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid SchleefAuthor: ds 28fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid SchleefUpdated: Mon, 18 Mar 2002 15:34:01 -0800 29fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid SchleefStatus: works 30fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 31fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid SchleefThis driver is a documented example on how Comedi drivers are 32fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefwritten. 33fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 34fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid SchleefConfiguration Options: 35fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef none 36fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef*/ 37fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 38fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 39fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * The previous block comment is used to automatically generate 40fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * documentation in Comedi and Comedilib. The fields: 41fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * 42fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Driver: the name of the driver 43fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Description: a short phrase describing the driver. Don't list boards. 44fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Devices: a full list of the boards that attempt to be supported by 45fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the driver. Format is "(manufacturer) board name [comedi name]", 46fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * where comedi_name is the name that is used to configure the board. 47fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * See the comment near board_name: in the comedi_driver structure 48fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * below. If (manufacturer) or [comedi name] is missing, the previous 49fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * value is used. 50fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Author: you 51fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Updated: date when the _documentation_ was last updated. Use 'date -R' 52fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * to get a value for this. 53fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Status: a one-word description of the status. Valid values are: 54fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * works - driver works correctly on most boards supported, and 55fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * passes comedi_test. 56fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * unknown - unknown. Usually put there by ds. 57fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * experimental - may not work in any particular release. Author 58fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * probably wants assistance testing it. 59fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * bitrotten - driver has not been update in a long time, probably 60fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * doesn't work, and probably is missing support for significant 61fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Comedi interface features. 62fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * untested - author probably wrote it "blind", and is believed to 63fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * work, but no confirmation. 64fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * 65fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * These headers should be followed by a blank line, and any comments 66fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * you wish to say about the driver. The comment area is the place 67fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * to put any known bugs, limitations, unsupported features, supported 68fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * command triggers, whether or not commands are supported on particular 69fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * subdevices, etc. 70fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * 71fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Somewhere in the comment should be information about configuration 72fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * options that are used with comedi_config. 73fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 74fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 75fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#include "../comedidev.h" 76fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 77fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#include <linux/pci.h> /* for PCI devices */ 78fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 79fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* Imaginary registers for the imaginary board */ 80fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 81fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define SKEL_SIZE 0 82fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 83fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define SKEL_START_AI_CONV 0 84fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define SKEL_AI_READ 0 85fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 86fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 87fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Board descriptions for two imaginary boards. Describing the 88fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * boards in this way is optional, and completely driver-dependent. 89fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Some drivers use arrays such as this, other do not. 90fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 91fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleeftypedef struct skel_board_struct { 92fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef const char *name; 93fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int ai_chans; 94fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int ai_bits; 95fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int have_dio; 96fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} skel_board; 97fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic const skel_board skel_boards[] = { 98fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef { 99fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef name: "skel-100", 100fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef ai_chans:16, 101fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef ai_bits: 12, 102fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef have_dio:1, 103fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef }, 104fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef { 105fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef name: "skel-200", 106fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef ai_chans:8, 107fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef ai_bits: 16, 108fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef have_dio:0, 109fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef }, 110fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef}; 111fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 112fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* This is used by modprobe to translate PCI IDs to drivers. Should 113fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * only be used for PCI and ISA-PnP devices */ 114fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded 115fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * upstream. */ 116fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define PCI_VENDOR_ID_SKEL 0xdafe 117fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic DEFINE_PCI_DEVICE_TABLE(skel_pci_table) = { 118fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef {PCI_VENDOR_ID_SKEL, 0x0100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 119fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef {PCI_VENDOR_ID_SKEL, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 120fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef {0} 121fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef}; 122fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 123fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid SchleefMODULE_DEVICE_TABLE(pci, skel_pci_table); 124fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 125fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 126fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Useful for shorthand access to the particular board structure 127fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 128fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define thisboard ((const skel_board *)dev->board_ptr) 129fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 130fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* this structure is for data unique to this hardware driver. If 131fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef several hardware drivers keep similar information in this structure, 132fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef feel free to suggest moving the variable to the comedi_device struct. */ 133fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleeftypedef struct { 134fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int data; 135fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 136fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* would be useful for a PCI device */ 137fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef struct pci_dev *pci_dev; 138fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 139fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* Used for AO readback */ 140fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef lsampl_t ao_readback[2]; 141fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} skel_private; 142fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 143fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * most drivers define the following macro to make it easy to 144fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * access the private structure. 145fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 146fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define devpriv ((skel_private *)dev->private) 147fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 148fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 149fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * The comedi_driver structure tells the Comedi core module 150fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * which functions to call to configure/deconfigure (attach/detach) 151fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the board, and also about the kernel module that contains 152fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the device code. 153fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 154fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_attach(comedi_device * dev, comedi_devconfig * it); 155fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_detach(comedi_device * dev); 156fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic comedi_driver driver_skel = { 157fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef driver_name:"dummy", 158fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef module:THIS_MODULE, 159fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef attach:skel_attach, 160fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef detach:skel_detach, 161fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* It is not necessary to implement the following members if you are 162fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * writing a driver for a ISA PnP or PCI card */ 163fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* Most drivers will support multiple types of boards by 164fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * having an array of board structures. These were defined 165fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * in skel_boards[] above. Note that the element 'name' 166fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * was first in the structure -- Comedi uses this fact to 167fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * extract the name of the board without knowing any details 168fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * about the structure except for its length. 169fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * When a device is attached (by comedi_config), the name 170fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * of the device is given to Comedi, and Comedi tries to 171fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * match it by going through the list of board names. If 172fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * there is a match, the address of the pointer is put 173fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * into dev->board_ptr and driver->attach() is called. 174fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * 175fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Note that these are not necessary if you can determine 176fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the type of board in software. ISA PnP, PCI, and PCMCIA 177fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * devices are such boards. 178fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 179fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef board_name:&skel_boards[0].name, 180fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef offset:sizeof(skel_board), 181fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef num_names:sizeof(skel_boards) / sizeof(skel_board), 182fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef}; 183fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 184fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_ai_rinsn(comedi_device * dev, comedi_subdevice * s, 185fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef comedi_insn * insn, lsampl_t * data); 186fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_ao_winsn(comedi_device * dev, comedi_subdevice * s, 187fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef comedi_insn * insn, lsampl_t * data); 188fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_ao_rinsn(comedi_device * dev, comedi_subdevice * s, 189fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef comedi_insn * insn, lsampl_t * data); 190fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_dio_insn_bits(comedi_device * dev, comedi_subdevice * s, 191fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef comedi_insn * insn, lsampl_t * data); 192fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_dio_insn_config(comedi_device * dev, comedi_subdevice * s, 193fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef comedi_insn * insn, lsampl_t * data); 194fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_ai_cmdtest(comedi_device * dev, comedi_subdevice * s, 195fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef comedi_cmd * cmd); 196fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_ns_to_timer(unsigned int *ns, int round); 197fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 198fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 199fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Attach is called by the Comedi core to configure the driver 200fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * for a particular board. If you specified a board_name array 201fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * in the driver structure, dev->board_ptr contains that 202fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * address. 203fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 204fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_attach(comedi_device * dev, comedi_devconfig * it) 205fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 206fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef comedi_subdevice *s; 207fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 208fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef printk("comedi%d: skel: ", dev->minor); 209fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 210fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 211fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * If you can probe the device to determine what device in a series 212fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * it is, this is the place to do it. Otherwise, dev->board_ptr 213fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * should already be initialized. 214fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 215fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //dev->board_ptr = skel_probe(dev, it); 216fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 217fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 218fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Initialize dev->board_name. Note that we can use the "thisboard" 219fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * macro now, since we just initialized it in the last line. 220fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 221fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef dev->board_name = thisboard->name; 222fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 223fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 224fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Allocate the private structure area. alloc_private() is a 225fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * convenient macro defined in comedidev.h. 226fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 227fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (alloc_private(dev, sizeof(skel_private)) < 0) 228fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return -ENOMEM; 229fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 230fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 231fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Allocate the subdevice structures. alloc_subdevice() is a 232fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * convenient macro defined in comedidev.h. 233fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 234fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (alloc_subdevices(dev, 3) < 0) 235fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return -ENOMEM; 236fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 237fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s = dev->subdevices + 0; 238fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //dev->read_subdev=s; 239fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* analog input subdevice */ 240fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->type = COMEDI_SUBD_AI; 241fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* we support single-ended (ground) and differential */ 242fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; 243fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->n_chan = thisboard->ai_chans; 244fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->maxdata = (1 << thisboard->ai_bits) - 1; 245fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->range_table = &range_bipolar10; 246fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->len_chanlist = 16; /* This is the maximum chanlist length that 247fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef the board can handle */ 248fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->insn_read = skel_ai_rinsn; 249fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef// s->subdev_flags |= SDF_CMD_READ; 250fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef// s->do_cmd = skel_ai_cmd; 251fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->do_cmdtest = skel_ai_cmdtest; 252fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 253fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s = dev->subdevices + 1; 254fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* analog output subdevice */ 255fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->type = COMEDI_SUBD_AO; 256fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->subdev_flags = SDF_WRITABLE; 257fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->n_chan = 1; 258fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->maxdata = 0xffff; 259fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->range_table = &range_bipolar5; 260fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->insn_write = skel_ao_winsn; 261fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->insn_read = skel_ao_rinsn; 262fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 263fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s = dev->subdevices + 2; 264fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* digital i/o subdevice */ 265fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (thisboard->have_dio) { 266fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->type = COMEDI_SUBD_DIO; 267fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 268fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->n_chan = 16; 269fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->maxdata = 1; 270fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->range_table = &range_digital; 271fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->insn_bits = skel_dio_insn_bits; 272fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->insn_config = skel_dio_insn_config; 273fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } else { 274fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->type = COMEDI_SUBD_UNUSED; 275fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 276fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 277fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef printk("attached\n"); 278fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 279fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return 0; 280fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 281fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 282fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 283fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * _detach is called to deconfigure a device. It should deallocate 284fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * resources. 285fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * This function is also called when _attach() fails, so it should be 286fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * careful not to release resources that were not necessarily 287fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * allocated by _attach(). dev->private and dev->subdevices are 288fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * deallocated automatically by the core. 289fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 290fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_detach(comedi_device * dev) 291fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 292fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef printk("comedi%d: skel: remove\n", dev->minor); 293fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 294fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return 0; 295fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 296fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 297fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 298fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * "instructions" read/write data in "one-shot" or "software-triggered" 299fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * mode. 300fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 301fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_ai_rinsn(comedi_device * dev, comedi_subdevice * s, 302fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef comedi_insn * insn, lsampl_t * data) 303fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 304fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int n, i; 305fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef unsigned int d; 306fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef unsigned int status; 307fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 308fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* a typical programming sequence */ 309fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 310fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* write channel to multiplexer */ 311fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //outw(chan,dev->iobase + SKEL_MUX); 312fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 313fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* don't wait for mux to settle */ 314fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 315fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* convert n samples */ 316fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef for (n = 0; n < insn->n; n++) { 317fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* trigger conversion */ 318fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //outw(0,dev->iobase + SKEL_CONVERT); 319fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 320fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define TIMEOUT 100 321fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* wait for conversion to end */ 322fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef for (i = 0; i < TIMEOUT; i++) { 323fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef status = 1; 324fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //status = inb(dev->iobase + SKEL_STATUS); 325fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (status) 326fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef break; 327fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 328fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (i == TIMEOUT) { 329fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* rt_printk() should be used instead of printk() 330fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * whenever the code can be called from real-time. */ 331fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef rt_printk("timeout\n"); 332fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return -ETIMEDOUT; 333fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 334fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 335fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* read data */ 336fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //d = inw(dev->iobase + SKEL_AI_DATA); 337fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef d = 0; 338fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 339fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* mangle the data as necessary */ 340fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef d ^= 1 << (thisboard->ai_bits - 1); 341fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 342fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef data[n] = d; 343fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 344fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 345fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* return the number of samples read/written */ 346fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return n; 347fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 348fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 349fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_ai_cmdtest(comedi_device * dev, comedi_subdevice * s, 350fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef comedi_cmd * cmd) 351fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 352fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int err = 0; 353fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int tmp; 354fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 355fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* cmdtest tests a particular command to see if it is valid. 356fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Using the cmdtest ioctl, a user can create a valid cmd 357fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * and then have it executes by the cmd ioctl. 358fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * 359fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * cmdtest returns 1,2,3,4 or 0, depending on which tests 360fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the command passes. */ 361fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 362fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* step 1: make sure trigger sources are trivially valid */ 363fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 364fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef tmp = cmd->start_src; 365fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->start_src &= TRIG_NOW; 366fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (!cmd->start_src || tmp != cmd->start_src) 367fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 368fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 369fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef tmp = cmd->scan_begin_src; 370fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; 371fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 372fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 373fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 374fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef tmp = cmd->convert_src; 375fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->convert_src &= TRIG_TIMER | TRIG_EXT; 376fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (!cmd->convert_src || tmp != cmd->convert_src) 377fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 378fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 379fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef tmp = cmd->scan_end_src; 380fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_end_src &= TRIG_COUNT; 381fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 382fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 383fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 384fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef tmp = cmd->stop_src; 385fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->stop_src &= TRIG_COUNT | TRIG_NONE; 386fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (!cmd->stop_src || tmp != cmd->stop_src) 387fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 388fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 389fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (err) 390fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return 1; 391fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 392fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* step 2: make sure trigger sources are unique and mutually compatible */ 393fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 394fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* note that mutual compatiblity is not an issue here */ 395fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->scan_begin_src != TRIG_TIMER && 396fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_begin_src != TRIG_EXT) 397fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 398fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) 399fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 400fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) 401fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 402fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 403fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (err) 404fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return 2; 405fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 406fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* step 3: make sure arguments are trivially compatible */ 407fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 408fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->start_arg != 0) { 409fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->start_arg = 0; 410fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 411fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 412fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define MAX_SPEED 10000 /* in nanoseconds */ 413fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define MIN_SPEED 1000000000 /* in nanoseconds */ 414fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 415fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->scan_begin_src == TRIG_TIMER) { 416fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->scan_begin_arg < MAX_SPEED) { 417fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_begin_arg = MAX_SPEED; 418fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 419fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 420fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->scan_begin_arg > MIN_SPEED) { 421fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_begin_arg = MIN_SPEED; 422fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 423fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 424fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } else { 425fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* external trigger */ 426fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* should be level/edge, hi/lo specification here */ 427fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* should specify multiple external triggers */ 428fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->scan_begin_arg > 9) { 429fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_begin_arg = 9; 430fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 431fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 432fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 433fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->convert_src == TRIG_TIMER) { 434fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->convert_arg < MAX_SPEED) { 435fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->convert_arg = MAX_SPEED; 436fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 437fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 438fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->convert_arg > MIN_SPEED) { 439fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->convert_arg = MIN_SPEED; 440fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 441fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 442fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } else { 443fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* external trigger */ 444fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* see above */ 445fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->convert_arg > 9) { 446fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->convert_arg = 9; 447fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 448fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 449fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 450fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 451fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->scan_end_arg != cmd->chanlist_len) { 452fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_end_arg = cmd->chanlist_len; 453fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 454fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 455fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->stop_src == TRIG_COUNT) { 456fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->stop_arg > 0x00ffffff) { 457fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->stop_arg = 0x00ffffff; 458fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 459fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 460fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } else { 461fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* TRIG_NONE */ 462fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->stop_arg != 0) { 463fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->stop_arg = 0; 464fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 465fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 466fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 467fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 468fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (err) 469fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return 3; 470fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 471fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* step 4: fix up any arguments */ 472fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 473fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->scan_begin_src == TRIG_TIMER) { 474fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef tmp = cmd->scan_begin_arg; 475fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef skel_ns_to_timer(&cmd->scan_begin_arg, 476fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->flags & TRIG_ROUND_MASK); 477fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (tmp != cmd->scan_begin_arg) 478fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 479fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 480fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->convert_src == TRIG_TIMER) { 481fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef tmp = cmd->convert_arg; 482fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef skel_ns_to_timer(&cmd->convert_arg, 483fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->flags & TRIG_ROUND_MASK); 484fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (tmp != cmd->convert_arg) 485fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 486fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->scan_begin_src == TRIG_TIMER && 487fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_begin_arg < 488fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->convert_arg * cmd->scan_end_arg) { 489fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_begin_arg = 490fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->convert_arg * cmd->scan_end_arg; 491fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 492fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 493fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 494fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 495fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (err) 496fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return 4; 497fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 498fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return 0; 499fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 500fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 501fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* This function doesn't require a particular form, this is just 502fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * what happens to be used in some of the drivers. It should 503fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * convert ns nanoseconds to a counter value suitable for programming 504fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the device. Also, it should adjust ns so that it cooresponds to 505fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the actual time that the device will use. */ 506fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_ns_to_timer(unsigned int *ns, int round) 507fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 508fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* trivial timer */ 509fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* if your timing is done through two cascaded timers, the 510fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * i8253_cascade_ns_to_timer() function in 8253.h can be 511fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * very helpful. There are also i8254_load() and i8254_mm_load() 512fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * which can be used to load values into the ubiquitous 8254 counters 513fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 514fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 515fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return *ns; 516fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 517fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 518fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_ao_winsn(comedi_device * dev, comedi_subdevice * s, 519fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef comedi_insn * insn, lsampl_t * data) 520fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 521fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int i; 522fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int chan = CR_CHAN(insn->chanspec); 523fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 524fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef printk("skel_ao_winsn\n"); 525fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* Writing a list of values to an AO channel is probably not 526fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * very useful, but that's how the interface is defined. */ 527fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef for (i = 0; i < insn->n; i++) { 528fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* a typical programming sequence */ 529fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //outw(data[i],dev->iobase + SKEL_DA0 + chan); 530fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef devpriv->ao_readback[chan] = data[i]; 531fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 532fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 533fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* return the number of samples read/written */ 534fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return i; 535fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 536fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 537fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* AO subdevices should have a read insn as well as a write insn. 538fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Usually this means copying a value stored in devpriv. */ 539fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_ao_rinsn(comedi_device * dev, comedi_subdevice * s, 540fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef comedi_insn * insn, lsampl_t * data) 541fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 542fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int i; 543fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int chan = CR_CHAN(insn->chanspec); 544fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 545fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef for (i = 0; i < insn->n; i++) 546fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef data[i] = devpriv->ao_readback[chan]; 547fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 548fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return i; 549fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 550fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 551fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* DIO devices are slightly special. Although it is possible to 552fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * implement the insn_read/insn_write interface, it is much more 553fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * useful to applications if you implement the insn_bits interface. 554fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * This allows packed reading/writing of the DIO channels. The 555fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * comedi core can convert between insn_bits and insn_read/write */ 556fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_dio_insn_bits(comedi_device * dev, comedi_subdevice * s, 557fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef comedi_insn * insn, lsampl_t * data) 558fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 559fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (insn->n != 2) 560fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return -EINVAL; 561fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 562fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* The insn data is a mask in data[0] and the new data 563fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * in data[1], each channel cooresponding to a bit. */ 564fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (data[0]) { 565fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->state &= ~data[0]; 566fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->state |= data[0] & data[1]; 567fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* Write out the new digital output lines */ 568fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //outw(s->state,dev->iobase + SKEL_DIO); 569fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 570fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 571fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* on return, data[1] contains the value of the digital 572fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * input and output lines. */ 573fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //data[1]=inw(dev->iobase + SKEL_DIO); 574fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* or we could just return the software copy of the output values if 575fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * it was a purely digital output subdevice */ 576fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //data[1]=s->state; 577fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 578fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return 2; 579fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 580fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 581fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_dio_insn_config(comedi_device * dev, comedi_subdevice * s, 582fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef comedi_insn * insn, lsampl_t * data) 583fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 584fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int chan = CR_CHAN(insn->chanspec); 585fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 586fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* The input or output configuration of each digital line is 587fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * configured by a special insn_config instruction. chanspec 588fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * contains the channel to be changed, and data[0] contains the 589fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * value COMEDI_INPUT or COMEDI_OUTPUT. */ 590fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef switch (data[0]) { 591fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef case INSN_CONFIG_DIO_OUTPUT: 592fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->io_bits |= 1 << chan; 593fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef break; 594fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef case INSN_CONFIG_DIO_INPUT: 595fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->io_bits &= ~(1 << chan); 596fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef break; 597fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef case INSN_CONFIG_DIO_QUERY: 598fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef data[1] = 599fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef (s-> 600fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; 601fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return insn->n; 602fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef break; 603fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef default: 604fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return -EINVAL; 605fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef break; 606fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 607fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //outw(s->io_bits,dev->iobase + SKEL_DIO_CONFIG); 608fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 609fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return insn->n; 610fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 611fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 612fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 613fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * A convenient macro that defines init_module() and cleanup_module(), 614fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * as necessary. 615fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 616fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid SchleefCOMEDI_INITCLEANUP(driver_skel); 617fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* If you are writing a PCI driver you should use COMEDI_PCI_INITCLEANUP instead. 618fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef*/ 619fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef// COMEDI_PCI_INITCLEANUP(driver_skel, skel_pci_table) 620