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