skel.c revision c1dd2fa6a12bfba92d3522fa43173480f52dbaed
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. 47139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pemberton * See the comment near board_name: in the struct 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 */ 91c1dd2fa6a12bfba92d3522fa43173480f52dbaedBill Pembertonstruct skel_board { 92fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef const char *name; 93fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int ai_chans; 94fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int ai_bits; 95fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int have_dio; 96c1dd2fa6a12bfba92d3522fa43173480f52dbaedBill Pemberton}; 97c1dd2fa6a12bfba92d3522fa43173480f52dbaedBill Pemberton 98c1dd2fa6a12bfba92d3522fa43173480f52dbaedBill Pembertonstatic const struct skel_board skel_boards[] = { 99fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef { 100fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef name: "skel-100", 101fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef ai_chans:16, 102fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef ai_bits: 12, 103fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef have_dio:1, 104fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef }, 105fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef { 106fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef name: "skel-200", 107fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef ai_chans:8, 108fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef ai_bits: 16, 109fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef have_dio:0, 110fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef }, 111fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef}; 112fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 113fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* This is used by modprobe to translate PCI IDs to drivers. Should 114fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * only be used for PCI and ISA-PnP devices */ 115fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded 116fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * upstream. */ 117fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define PCI_VENDOR_ID_SKEL 0xdafe 118fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic DEFINE_PCI_DEVICE_TABLE(skel_pci_table) = { 119fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef {PCI_VENDOR_ID_SKEL, 0x0100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 120fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef {PCI_VENDOR_ID_SKEL, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 121fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef {0} 122fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef}; 123fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 124fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid SchleefMODULE_DEVICE_TABLE(pci, skel_pci_table); 125fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 126fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 127fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Useful for shorthand access to the particular board structure 128fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 129c1dd2fa6a12bfba92d3522fa43173480f52dbaedBill Pemberton#define thisboard ((const struct skel_board *)dev->board_ptr) 130fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 131fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* this structure is for data unique to this hardware driver. If 132fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef several hardware drivers keep similar information in this structure, 13371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton feel free to suggest moving the variable to the struct comedi_device struct. */ 134fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleeftypedef struct { 135fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int data; 136fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 137fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* would be useful for a PCI device */ 138fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef struct pci_dev *pci_dev; 139fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 140fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* Used for AO readback */ 141790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton unsigned int ao_readback[2]; 142fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} skel_private; 143fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 144fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * most drivers define the following macro to make it easy to 145fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * access the private structure. 146fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 147fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define devpriv ((skel_private *)dev->private) 148fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 149fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 150139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pemberton * The struct comedi_driver structure tells the Comedi core module 151fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * which functions to call to configure/deconfigure (attach/detach) 152fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the board, and also about the kernel module that contains 153fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the device code. 154fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 1550707bb04be89b18ee83b5a997e36cc585f0b988dBill Pembertonstatic int skel_attach(struct comedi_device * dev, struct comedi_devconfig * it); 15671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int skel_detach(struct comedi_device * dev); 157139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pembertonstatic struct comedi_driver driver_skel = { 158fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef driver_name:"dummy", 159fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef module:THIS_MODULE, 160fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef attach:skel_attach, 161fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef detach:skel_detach, 162fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* It is not necessary to implement the following members if you are 163fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * writing a driver for a ISA PnP or PCI card */ 164fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* Most drivers will support multiple types of boards by 165fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * having an array of board structures. These were defined 166fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * in skel_boards[] above. Note that the element 'name' 167fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * was first in the structure -- Comedi uses this fact to 168fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * extract the name of the board without knowing any details 169fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * about the structure except for its length. 170fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * When a device is attached (by comedi_config), the name 171fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * of the device is given to Comedi, and Comedi tries to 172fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * match it by going through the list of board names. If 173fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * there is a match, the address of the pointer is put 174fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * into dev->board_ptr and driver->attach() is called. 175fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * 176fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Note that these are not necessary if you can determine 177fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the type of board in software. ISA PnP, PCI, and PCMCIA 178fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * devices are such boards. 179fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 180fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef board_name:&skel_boards[0].name, 181c1dd2fa6a12bfba92d3522fa43173480f52dbaedBill Pemberton offset:sizeof(struct skel_board), 182c1dd2fa6a12bfba92d3522fa43173480f52dbaedBill Pemberton num_names:sizeof(skel_boards) / sizeof(struct skel_board), 183fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef}; 184fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 18534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int skel_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, 18690035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton struct comedi_insn * insn, unsigned int * data); 18734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int skel_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, 18890035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton struct comedi_insn * insn, unsigned int * data); 18934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int skel_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, 19090035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton struct comedi_insn * insn, unsigned int * data); 19134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int skel_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, 19290035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton struct comedi_insn * insn, unsigned int * data); 19334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int skel_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, 19490035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton struct comedi_insn * insn, unsigned int * data); 19534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int skel_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, 196ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton struct comedi_cmd * cmd); 197fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_ns_to_timer(unsigned int *ns, int round); 198fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 199fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 200fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Attach is called by the Comedi core to configure the driver 201fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * for a particular board. If you specified a board_name array 202fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * in the driver structure, dev->board_ptr contains that 203fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * address. 204fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 2050707bb04be89b18ee83b5a997e36cc585f0b988dBill Pembertonstatic int skel_attach(struct comedi_device * dev, struct comedi_devconfig * it) 206fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 20734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 208fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 209fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef printk("comedi%d: skel: ", dev->minor); 210fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 211fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 212fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * If you can probe the device to determine what device in a series 213fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * it is, this is the place to do it. Otherwise, dev->board_ptr 214fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * should already be initialized. 215fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 216fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //dev->board_ptr = skel_probe(dev, it); 217fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 218fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 219fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Initialize dev->board_name. Note that we can use the "thisboard" 220fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * macro now, since we just initialized it in the last line. 221fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 222fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef dev->board_name = thisboard->name; 223fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 224fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 225fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Allocate the private structure area. alloc_private() is a 226fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * convenient macro defined in comedidev.h. 227fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 228fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (alloc_private(dev, sizeof(skel_private)) < 0) 229fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return -ENOMEM; 230fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 231fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 232fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Allocate the subdevice structures. alloc_subdevice() is a 233fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * convenient macro defined in comedidev.h. 234fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 235fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (alloc_subdevices(dev, 3) < 0) 236fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return -ENOMEM; 237fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 238fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s = dev->subdevices + 0; 239fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //dev->read_subdev=s; 240fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* analog input subdevice */ 241fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->type = COMEDI_SUBD_AI; 242fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* we support single-ended (ground) and differential */ 243fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; 244fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->n_chan = thisboard->ai_chans; 245fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->maxdata = (1 << thisboard->ai_bits) - 1; 246fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->range_table = &range_bipolar10; 247fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->len_chanlist = 16; /* This is the maximum chanlist length that 248fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef the board can handle */ 249fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->insn_read = skel_ai_rinsn; 250fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef// s->subdev_flags |= SDF_CMD_READ; 251fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef// s->do_cmd = skel_ai_cmd; 252fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->do_cmdtest = skel_ai_cmdtest; 253fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 254fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s = dev->subdevices + 1; 255fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* analog output subdevice */ 256fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->type = COMEDI_SUBD_AO; 257fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->subdev_flags = SDF_WRITABLE; 258fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->n_chan = 1; 259fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->maxdata = 0xffff; 260fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->range_table = &range_bipolar5; 261fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->insn_write = skel_ao_winsn; 262fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->insn_read = skel_ao_rinsn; 263fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 264fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s = dev->subdevices + 2; 265fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* digital i/o subdevice */ 266fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (thisboard->have_dio) { 267fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->type = COMEDI_SUBD_DIO; 268fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 269fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->n_chan = 16; 270fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->maxdata = 1; 271fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->range_table = &range_digital; 272fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->insn_bits = skel_dio_insn_bits; 273fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->insn_config = skel_dio_insn_config; 274fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } else { 275fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->type = COMEDI_SUBD_UNUSED; 276fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 277fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 278fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef printk("attached\n"); 279fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 280fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return 0; 281fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 282fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 283fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 284fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * _detach is called to deconfigure a device. It should deallocate 285fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * resources. 286fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * This function is also called when _attach() fails, so it should be 287fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * careful not to release resources that were not necessarily 288fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * allocated by _attach(). dev->private and dev->subdevices are 289fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * deallocated automatically by the core. 290fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 29171b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int skel_detach(struct comedi_device * dev) 292fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 293fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef printk("comedi%d: skel: remove\n", dev->minor); 294fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 295fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return 0; 296fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 297fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 298fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 299fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * "instructions" read/write data in "one-shot" or "software-triggered" 300fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * mode. 301fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 30234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int skel_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, 30390035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton struct comedi_insn * insn, unsigned int * data) 304fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 305fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int n, i; 306fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef unsigned int d; 307fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef unsigned int status; 308fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 309fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* a typical programming sequence */ 310fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 311fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* write channel to multiplexer */ 312fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //outw(chan,dev->iobase + SKEL_MUX); 313fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 314fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* don't wait for mux to settle */ 315fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 316fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* convert n samples */ 317fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef for (n = 0; n < insn->n; n++) { 318fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* trigger conversion */ 319fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //outw(0,dev->iobase + SKEL_CONVERT); 320fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 321fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define TIMEOUT 100 322fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* wait for conversion to end */ 323fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef for (i = 0; i < TIMEOUT; i++) { 324fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef status = 1; 325fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //status = inb(dev->iobase + SKEL_STATUS); 326fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (status) 327fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef break; 328fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 329fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (i == TIMEOUT) { 330fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* rt_printk() should be used instead of printk() 331fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * whenever the code can be called from real-time. */ 332fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef rt_printk("timeout\n"); 333fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return -ETIMEDOUT; 334fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 335fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 336fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* read data */ 337fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //d = inw(dev->iobase + SKEL_AI_DATA); 338fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef d = 0; 339fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 340fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* mangle the data as necessary */ 341fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef d ^= 1 << (thisboard->ai_bits - 1); 342fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 343fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef data[n] = d; 344fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 345fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 346fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* return the number of samples read/written */ 347fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return n; 348fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 349fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 35034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int skel_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, 351ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton struct comedi_cmd * cmd) 352fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 353fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int err = 0; 354fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int tmp; 355fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 356fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* cmdtest tests a particular command to see if it is valid. 357fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Using the cmdtest ioctl, a user can create a valid cmd 358fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * and then have it executes by the cmd ioctl. 359fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * 360fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * cmdtest returns 1,2,3,4 or 0, depending on which tests 361fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the command passes. */ 362fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 363fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* step 1: make sure trigger sources are trivially valid */ 364fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 365fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef tmp = cmd->start_src; 366fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->start_src &= TRIG_NOW; 367fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (!cmd->start_src || tmp != cmd->start_src) 368fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 369fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 370fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef tmp = cmd->scan_begin_src; 371fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; 372fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 373fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 374fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 375fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef tmp = cmd->convert_src; 376fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->convert_src &= TRIG_TIMER | TRIG_EXT; 377fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (!cmd->convert_src || tmp != cmd->convert_src) 378fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 379fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 380fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef tmp = cmd->scan_end_src; 381fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_end_src &= TRIG_COUNT; 382fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 383fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 384fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 385fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef tmp = cmd->stop_src; 386fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->stop_src &= TRIG_COUNT | TRIG_NONE; 387fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (!cmd->stop_src || tmp != cmd->stop_src) 388fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 389fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 390fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (err) 391fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return 1; 392fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 393fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* step 2: make sure trigger sources are unique and mutually compatible */ 394fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 395fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* note that mutual compatiblity is not an issue here */ 396fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->scan_begin_src != TRIG_TIMER && 397fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_begin_src != TRIG_EXT) 398fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 399fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) 400fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 401fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) 402fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 403fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 404fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (err) 405fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return 2; 406fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 407fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* step 3: make sure arguments are trivially compatible */ 408fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 409fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->start_arg != 0) { 410fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->start_arg = 0; 411fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 412fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 413fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define MAX_SPEED 10000 /* in nanoseconds */ 414fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define MIN_SPEED 1000000000 /* in nanoseconds */ 415fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 416fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->scan_begin_src == TRIG_TIMER) { 417fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->scan_begin_arg < MAX_SPEED) { 418fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_begin_arg = MAX_SPEED; 419fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 420fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 421fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->scan_begin_arg > MIN_SPEED) { 422fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_begin_arg = MIN_SPEED; 423fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 424fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 425fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } else { 426fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* external trigger */ 427fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* should be level/edge, hi/lo specification here */ 428fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* should specify multiple external triggers */ 429fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->scan_begin_arg > 9) { 430fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_begin_arg = 9; 431fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 432fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 433fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 434fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->convert_src == TRIG_TIMER) { 435fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->convert_arg < MAX_SPEED) { 436fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->convert_arg = MAX_SPEED; 437fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 438fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 439fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->convert_arg > MIN_SPEED) { 440fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->convert_arg = MIN_SPEED; 441fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 442fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 443fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } else { 444fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* external trigger */ 445fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* see above */ 446fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->convert_arg > 9) { 447fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->convert_arg = 9; 448fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 449fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 450fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 451fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 452fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->scan_end_arg != cmd->chanlist_len) { 453fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_end_arg = cmd->chanlist_len; 454fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 455fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 456fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->stop_src == TRIG_COUNT) { 457fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->stop_arg > 0x00ffffff) { 458fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->stop_arg = 0x00ffffff; 459fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 460fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 461fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } else { 462fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* TRIG_NONE */ 463fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->stop_arg != 0) { 464fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->stop_arg = 0; 465fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 466fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 467fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 468fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 469fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (err) 470fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return 3; 471fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 472fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* step 4: fix up any arguments */ 473fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 474fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->scan_begin_src == TRIG_TIMER) { 475fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef tmp = cmd->scan_begin_arg; 476fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef skel_ns_to_timer(&cmd->scan_begin_arg, 477fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->flags & TRIG_ROUND_MASK); 478fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (tmp != cmd->scan_begin_arg) 479fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 480fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 481fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->convert_src == TRIG_TIMER) { 482fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef tmp = cmd->convert_arg; 483fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef skel_ns_to_timer(&cmd->convert_arg, 484fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->flags & TRIG_ROUND_MASK); 485fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (tmp != cmd->convert_arg) 486fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 487fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (cmd->scan_begin_src == TRIG_TIMER && 488fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_begin_arg < 489fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->convert_arg * cmd->scan_end_arg) { 490fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->scan_begin_arg = 491fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef cmd->convert_arg * cmd->scan_end_arg; 492fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef err++; 493fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 494fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 495fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 496fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (err) 497fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return 4; 498fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 499fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return 0; 500fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 501fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 502fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* This function doesn't require a particular form, this is just 503fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * what happens to be used in some of the drivers. It should 504fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * convert ns nanoseconds to a counter value suitable for programming 505fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the device. Also, it should adjust ns so that it cooresponds to 506fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the actual time that the device will use. */ 507fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_ns_to_timer(unsigned int *ns, int round) 508fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 509fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* trivial timer */ 510fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* if your timing is done through two cascaded timers, the 511fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * i8253_cascade_ns_to_timer() function in 8253.h can be 512fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * very helpful. There are also i8254_load() and i8254_mm_load() 513fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * which can be used to load values into the ubiquitous 8254 counters 514fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 515fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 516fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return *ns; 517fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 518fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 51934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int skel_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, 52090035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton struct comedi_insn * insn, unsigned int * data) 521fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 522fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int i; 523fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int chan = CR_CHAN(insn->chanspec); 524fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 525fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef printk("skel_ao_winsn\n"); 526fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* Writing a list of values to an AO channel is probably not 527fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * very useful, but that's how the interface is defined. */ 528fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef for (i = 0; i < insn->n; i++) { 529fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* a typical programming sequence */ 530fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //outw(data[i],dev->iobase + SKEL_DA0 + chan); 531fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef devpriv->ao_readback[chan] = data[i]; 532fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 533fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 534fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* return the number of samples read/written */ 535fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return i; 536fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 537fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 538fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* AO subdevices should have a read insn as well as a write insn. 539fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Usually this means copying a value stored in devpriv. */ 54034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int skel_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, 54190035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton struct comedi_insn * insn, unsigned int * data) 542fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 543fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int i; 544fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int chan = CR_CHAN(insn->chanspec); 545fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 546fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef for (i = 0; i < insn->n; i++) 547fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef data[i] = devpriv->ao_readback[chan]; 548fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 549fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return i; 550fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 551fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 552fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* DIO devices are slightly special. Although it is possible to 553fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * implement the insn_read/insn_write interface, it is much more 554fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * useful to applications if you implement the insn_bits interface. 555fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * This allows packed reading/writing of the DIO channels. The 556fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * comedi core can convert between insn_bits and insn_read/write */ 55734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int skel_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, 55890035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton struct comedi_insn * insn, unsigned int * data) 559fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 560fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (insn->n != 2) 561fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return -EINVAL; 562fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 563fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* The insn data is a mask in data[0] and the new data 564fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * in data[1], each channel cooresponding to a bit. */ 565fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef if (data[0]) { 566fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->state &= ~data[0]; 567fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->state |= data[0] & data[1]; 568fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* Write out the new digital output lines */ 569fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //outw(s->state,dev->iobase + SKEL_DIO); 570fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 571fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 572fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* on return, data[1] contains the value of the digital 573fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * input and output lines. */ 574fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //data[1]=inw(dev->iobase + SKEL_DIO); 575fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* or we could just return the software copy of the output values if 576fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * it was a purely digital output subdevice */ 577fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //data[1]=s->state; 578fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 579fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return 2; 580fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 581fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 58234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int skel_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, 58390035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton struct comedi_insn * insn, unsigned int * data) 584fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{ 585fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef int chan = CR_CHAN(insn->chanspec); 586fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 587fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef /* The input or output configuration of each digital line is 588fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * configured by a special insn_config instruction. chanspec 589fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * contains the channel to be changed, and data[0] contains the 590fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * value COMEDI_INPUT or COMEDI_OUTPUT. */ 591fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef switch (data[0]) { 592fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef case INSN_CONFIG_DIO_OUTPUT: 593fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->io_bits |= 1 << chan; 594fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef break; 595fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef case INSN_CONFIG_DIO_INPUT: 596fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef s->io_bits &= ~(1 << chan); 597fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef break; 598fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef case INSN_CONFIG_DIO_QUERY: 599fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef data[1] = 600fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef (s-> 601fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; 602fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return insn->n; 603fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef break; 604fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef default: 605fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return -EINVAL; 606fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef break; 607fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef } 608fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef //outw(s->io_bits,dev->iobase + SKEL_DIO_CONFIG); 609fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 610fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef return insn->n; 611fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef} 612fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef 613fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* 614fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * A convenient macro that defines init_module() and cleanup_module(), 615fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * as necessary. 616fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */ 617fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid SchleefCOMEDI_INITCLEANUP(driver_skel); 618fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* If you are writing a PCI driver you should use COMEDI_PCI_INITCLEANUP instead. 619fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef*/ 620fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef// COMEDI_PCI_INITCLEANUP(driver_skel, skel_pci_table) 621