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