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 *
429a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *  Driver: the name of the driver
439a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *  Description: a short phrase describing the driver.  Don't list boards.
449a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *  Devices: a full list of the boards that attempt to be supported by
459a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *    the driver.  Format is "(manufacturer) board name [comedi name]",
469a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *    where comedi_name is the name that is used to configure the board.
479a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *    See the comment near board_name: in the struct comedi_driver structure
489a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *    below.  If (manufacturer) or [comedi name] is missing, the previous
499a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *    value is used.
509a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *  Author: you
519a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *  Updated: date when the _documentation_ was last updated.  Use 'date -R'
529a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *    to get a value for this.
539a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *  Status: a one-word description of the status.  Valid values are:
549a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *    works - driver works correctly on most boards supported, and
559a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *      passes comedi_test.
569a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *    unknown - unknown.  Usually put there by ds.
579a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *    experimental - may not work in any particular release.  Author
589a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *      probably wants assistance testing it.
599a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *    bitrotten - driver has not been update in a long time, probably
609a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *      doesn't work, and probably is missing support for significant
619a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *      Comedi interface features.
629a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *    untested - author probably wrote it "blind", and is believed to
639a390f38b6a84d5a11c89a116363db3fe587598bIan Abbott *      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	{
1000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .name = "skel-100",
1010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_chans = 16,
1020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_bits = 12,
1030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .have_dio = 1,
1040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
105fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	{
1060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .name = "skel-200",
1070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_chans = 8,
1080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_bits = 16,
1090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .have_dio = 0,
1100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
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) = {
1197af6fb13cada6dfa8144d7c316c60bd7f8bd1ba9Javier Martinez Canillas	{ PCI_DEVICE(PCI_VENDOR_ID_SKEL, 0x0100) },
1207af6fb13cada6dfa8144d7c316c60bd7f8bd1ba9Javier Martinez Canillas	{ PCI_DEVICE(PCI_VENDOR_ID_SKEL, 0x0200) },
1217af6fb13cada6dfa8144d7c316c60bd7f8bd1ba9Javier Martinez Canillas	{ 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,
133588063a10f4e21cd3a2cc693c0c1ebb846ac4ce5Ellwyn Cole   feel free to suggest moving the variable to the struct comedi_device struct.
134588063a10f4e21cd3a2cc693c0c1ebb846ac4ce5Ellwyn Cole */
135404d108d8f5968f47ba72417a3532f213e020914Bill Pembertonstruct skel_private {
136404d108d8f5968f47ba72417a3532f213e020914Bill Pemberton
137fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	int data;
138fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
139fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* would be useful for a PCI device */
140fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	struct pci_dev *pci_dev;
141fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
142fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* Used for AO readback */
143790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int ao_readback[2];
144404d108d8f5968f47ba72417a3532f213e020914Bill Pemberton};
145404d108d8f5968f47ba72417a3532f213e020914Bill Pemberton
146fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/*
147fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * most drivers define the following macro to make it easy to
148fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * access the private structure.
149fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */
150404d108d8f5968f47ba72417a3532f213e020914Bill Pemberton#define devpriv ((struct skel_private *)dev->private)
151fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
152fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/*
153139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pemberton * The struct comedi_driver structure tells the Comedi core module
154fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * which functions to call to configure/deconfigure (attach/detach)
155fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the board, and also about the kernel module that contains
156fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the device code.
157fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */
158da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it);
159da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int skel_detach(struct comedi_device *dev);
160139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pembertonstatic struct comedi_driver driver_skel = {
16168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.driver_name = "dummy",
16268c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.module = THIS_MODULE,
16368c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.attach = skel_attach,
16468c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.detach = skel_detach,
165fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* It is not necessary to implement the following members if you are
166fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * writing a driver for a ISA PnP or PCI card */
167fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* Most drivers will support multiple types of boards by
168fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * having an array of board structures.  These were defined
169fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * in skel_boards[] above.  Note that the element 'name'
170fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * was first in the structure -- Comedi uses this fact to
171fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * extract the name of the board without knowing any details
172fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * about the structure except for its length.
173fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * When a device is attached (by comedi_config), the name
174fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * of the device is given to Comedi, and Comedi tries to
175fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * match it by going through the list of board names.  If
176fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * there is a match, the address of the pointer is put
177fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * into dev->board_ptr and driver->attach() is called.
178fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 *
179fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * Note that these are not necessary if you can determine
180fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * the type of board in software.  ISA PnP, PCI, and PCMCIA
181fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * devices are such boards.
182fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 */
18368c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.board_name = &skel_boards[0].name,
18468c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.offset = sizeof(struct skel_board),
1858629efa4cbf6f89a54a85af4b8bc31762af01800Bill Pemberton	.num_names = ARRAY_SIZE(skel_boards),
186fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef};
187fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
188da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 struct comedi_insn *insn, unsigned int *data);
190da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int skel_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
1910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 struct comedi_insn *insn, unsigned int *data);
192da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int skel_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 struct comedi_insn *insn, unsigned int *data);
1940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int skel_dio_insn_bits(struct comedi_device *dev,
1950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			      struct comedi_subdevice *s,
1960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			      struct comedi_insn *insn, unsigned int *data);
1970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int skel_dio_insn_config(struct comedi_device *dev,
1980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_subdevice *s,
1990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_insn *insn, unsigned int *data);
2000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int skel_ai_cmdtest(struct comedi_device *dev,
2010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   struct comedi_subdevice *s, struct comedi_cmd *cmd);
202fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_ns_to_timer(unsigned int *ns, int round);
203fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
204fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/*
205fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Attach is called by the Comedi core to configure the driver
206fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * for a particular board.  If you specified a board_name array
207fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * in the driver structure, dev->board_ptr contains that
208fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * address.
209fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */
210da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it)
211fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{
21234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
213fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
214588063a10f4e21cd3a2cc693c0c1ebb846ac4ce5Ellwyn Cole	pr_info("comedi%d: skel: ", dev->minor);
215fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
216fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/*
217fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * If you can probe the device to determine what device in a series
218fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * it is, this is the place to do it.  Otherwise, dev->board_ptr
219fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * should already be initialized.
220fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */
22197070b32a886d53b7343bcb28ed38d906fa95f50Bill Pemberton	/* dev->board_ptr = skel_probe(dev, it); */
222fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
223fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/*
224fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Initialize dev->board_name.  Note that we can use the "thisboard"
225fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * macro now, since we just initialized it in the last line.
226fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */
227fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	dev->board_name = thisboard->name;
228fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
229fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/*
230fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Allocate the private structure area.  alloc_private() is a
231fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * convenient macro defined in comedidev.h.
232fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */
233404d108d8f5968f47ba72417a3532f213e020914Bill Pemberton	if (alloc_private(dev, sizeof(struct skel_private)) < 0)
234fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		return -ENOMEM;
235fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
236fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/*
237fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Allocate the subdevice structures.  alloc_subdevice() is a
238fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * convenient macro defined in comedidev.h.
239fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */
240fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (alloc_subdevices(dev, 3) < 0)
241fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		return -ENOMEM;
242fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
243fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s = dev->subdevices + 0;
24497070b32a886d53b7343bcb28ed38d906fa95f50Bill Pemberton	/* dev->read_subdev=s; */
245fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* analog input subdevice */
246fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s->type = COMEDI_SUBD_AI;
247fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* we support single-ended (ground) and differential */
248fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
249fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s->n_chan = thisboard->ai_chans;
250fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s->maxdata = (1 << thisboard->ai_bits) - 1;
251fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s->range_table = &range_bipolar10;
252fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s->len_chanlist = 16;	/* This is the maximum chanlist length that
253fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef				   the board can handle */
254fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s->insn_read = skel_ai_rinsn;
25597070b32a886d53b7343bcb28ed38d906fa95f50Bill Pemberton/*
25697070b32a886d53b7343bcb28ed38d906fa95f50Bill Pemberton*       s->subdev_flags |= SDF_CMD_READ;
25797070b32a886d53b7343bcb28ed38d906fa95f50Bill Pemberton*       s->do_cmd = skel_ai_cmd;
25897070b32a886d53b7343bcb28ed38d906fa95f50Bill Pemberton*/
259fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s->do_cmdtest = skel_ai_cmdtest;
260fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
261fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s = dev->subdevices + 1;
262fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* analog output subdevice */
263fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s->type = COMEDI_SUBD_AO;
264fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s->subdev_flags = SDF_WRITABLE;
265fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s->n_chan = 1;
266fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s->maxdata = 0xffff;
267fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s->range_table = &range_bipolar5;
268fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s->insn_write = skel_ao_winsn;
269fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s->insn_read = skel_ao_rinsn;
270fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
271fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	s = dev->subdevices + 2;
272fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* digital i/o subdevice */
273fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (thisboard->have_dio) {
274fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		s->type = COMEDI_SUBD_DIO;
275fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
276fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		s->n_chan = 16;
277fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		s->maxdata = 1;
278fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		s->range_table = &range_digital;
279fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		s->insn_bits = skel_dio_insn_bits;
280fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		s->insn_config = skel_dio_insn_config;
281fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	} else {
282fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		s->type = COMEDI_SUBD_UNUSED;
283fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	}
284fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
285588063a10f4e21cd3a2cc693c0c1ebb846ac4ce5Ellwyn Cole	pr_info("attached\n");
286fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
287fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	return 0;
288fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef}
289fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
290fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/*
291fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * _detach is called to deconfigure a device.  It should deallocate
292fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * resources.
293fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * This function is also called when _attach() fails, so it should be
294fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * careful not to release resources that were not necessarily
295fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * allocated by _attach().  dev->private and dev->subdevices are
296fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * deallocated automatically by the core.
297fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */
298da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int skel_detach(struct comedi_device *dev)
299fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{
300588063a10f4e21cd3a2cc693c0c1ebb846ac4ce5Ellwyn Cole	pr_info("comedi%d: skel: remove\n", dev->minor);
301fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
302fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	return 0;
303fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef}
304fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
305fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/*
306fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * "instructions" read/write data in "one-shot" or "software-triggered"
307fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * mode.
308fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef */
309da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
3100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 struct comedi_insn *insn, unsigned int *data)
311fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{
312fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	int n, i;
313fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	unsigned int d;
314fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	unsigned int status;
315fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
316fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* a typical programming sequence */
317fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
318fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* write channel to multiplexer */
31997070b32a886d53b7343bcb28ed38d906fa95f50Bill Pemberton	/* outw(chan,dev->iobase + SKEL_MUX); */
320fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
321fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* don't wait for mux to settle */
322fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
323fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* convert n samples */
324fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	for (n = 0; n < insn->n; n++) {
325fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		/* trigger conversion */
32697070b32a886d53b7343bcb28ed38d906fa95f50Bill Pemberton		/* outw(0,dev->iobase + SKEL_CONVERT); */
327fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
328fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define TIMEOUT 100
329fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		/* wait for conversion to end */
330fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		for (i = 0; i < TIMEOUT; i++) {
331fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			status = 1;
33297070b32a886d53b7343bcb28ed38d906fa95f50Bill Pemberton			/* status = inb(dev->iobase + SKEL_STATUS); */
333fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			if (status)
334fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef				break;
335fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		}
336fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		if (i == TIMEOUT) {
3375f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman			/* printk() should be used instead of printk()
338fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			 * whenever the code can be called from real-time. */
339588063a10f4e21cd3a2cc693c0c1ebb846ac4ce5Ellwyn Cole			pr_info("timeout\n");
340fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			return -ETIMEDOUT;
341fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		}
342fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
343fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		/* read data */
34497070b32a886d53b7343bcb28ed38d906fa95f50Bill Pemberton		/* d = inw(dev->iobase + SKEL_AI_DATA); */
345fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		d = 0;
346fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
347fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		/* mangle the data as necessary */
348fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		d ^= 1 << (thisboard->ai_bits - 1);
349fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
350fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		data[n] = d;
351fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	}
352fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
353fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* return the number of samples read/written */
354fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	return n;
355fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef}
356fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
3570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int skel_ai_cmdtest(struct comedi_device *dev,
3580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   struct comedi_subdevice *s, struct comedi_cmd *cmd)
359fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{
360fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	int err = 0;
361fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	int tmp;
362fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
363fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* cmdtest tests a particular command to see if it is valid.
364fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * Using the cmdtest ioctl, a user can create a valid cmd
365fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * and then have it executes by the cmd ioctl.
366fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 *
367fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * cmdtest returns 1,2,3,4 or 0, depending on which tests
368fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * the command passes. */
369fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
370fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* step 1: make sure trigger sources are trivially valid */
371fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
372fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	tmp = cmd->start_src;
373fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	cmd->start_src &= TRIG_NOW;
374fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (!cmd->start_src || tmp != cmd->start_src)
375fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		err++;
376fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
377fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	tmp = cmd->scan_begin_src;
378fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
379fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
380fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		err++;
381fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
382fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	tmp = cmd->convert_src;
383fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
384fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (!cmd->convert_src || tmp != cmd->convert_src)
385fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		err++;
386fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
387fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	tmp = cmd->scan_end_src;
388fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	cmd->scan_end_src &= TRIG_COUNT;
389fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
390fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		err++;
391fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
392fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	tmp = cmd->stop_src;
393fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
394fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (!cmd->stop_src || tmp != cmd->stop_src)
395fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		err++;
396fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
397fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (err)
398fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		return 1;
399fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
400588063a10f4e21cd3a2cc693c0c1ebb846ac4ce5Ellwyn Cole	/* step 2: make sure trigger sources are unique and mutually compatible
401588063a10f4e21cd3a2cc693c0c1ebb846ac4ce5Ellwyn Cole     */
402fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
403828684f9a6e096f9150bad523c43b75d74b9baddDirk Hohndel	/* note that mutual compatibility is not an issue here */
404fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (cmd->scan_begin_src != TRIG_TIMER &&
4050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    cmd->scan_begin_src != TRIG_EXT)
406fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		err++;
407fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
408fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		err++;
409fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
410fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		err++;
411fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
412fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (err)
413fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		return 2;
414fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
415fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* step 3: make sure arguments are trivially compatible */
416fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
417fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (cmd->start_arg != 0) {
418fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		cmd->start_arg = 0;
419fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		err++;
420fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	}
421fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define MAX_SPEED	10000	/* in nanoseconds */
422fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef#define MIN_SPEED	1000000000	/* in nanoseconds */
423fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
424fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (cmd->scan_begin_src == TRIG_TIMER) {
425fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		if (cmd->scan_begin_arg < MAX_SPEED) {
426fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			cmd->scan_begin_arg = MAX_SPEED;
427fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			err++;
428fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		}
429fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		if (cmd->scan_begin_arg > MIN_SPEED) {
430fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			cmd->scan_begin_arg = MIN_SPEED;
431fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			err++;
432fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		}
433fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	} else {
434fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		/* external trigger */
435fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		/* should be level/edge, hi/lo specification here */
436fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		/* should specify multiple external triggers */
437fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		if (cmd->scan_begin_arg > 9) {
438fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			cmd->scan_begin_arg = 9;
439fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			err++;
440fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		}
441fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	}
442fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (cmd->convert_src == TRIG_TIMER) {
443fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		if (cmd->convert_arg < MAX_SPEED) {
444fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			cmd->convert_arg = MAX_SPEED;
445fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			err++;
446fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		}
447fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		if (cmd->convert_arg > MIN_SPEED) {
448fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			cmd->convert_arg = MIN_SPEED;
449fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			err++;
450fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		}
451fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	} else {
452fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		/* external trigger */
453fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		/* see above */
454fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		if (cmd->convert_arg > 9) {
455fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			cmd->convert_arg = 9;
456fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			err++;
457fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		}
458fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	}
459fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
460fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (cmd->scan_end_arg != cmd->chanlist_len) {
461fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		cmd->scan_end_arg = cmd->chanlist_len;
462fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		err++;
463fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	}
464fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (cmd->stop_src == TRIG_COUNT) {
465fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		if (cmd->stop_arg > 0x00ffffff) {
466fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			cmd->stop_arg = 0x00ffffff;
467fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			err++;
468fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		}
469fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	} else {
470fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		/* TRIG_NONE */
471fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		if (cmd->stop_arg != 0) {
472fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			cmd->stop_arg = 0;
473fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			err++;
474fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		}
475fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	}
476fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
477fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (err)
478fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		return 3;
479fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
480fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* step 4: fix up any arguments */
481fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
482fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (cmd->scan_begin_src == TRIG_TIMER) {
483fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		tmp = cmd->scan_begin_arg;
484fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		skel_ns_to_timer(&cmd->scan_begin_arg,
4850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 cmd->flags & TRIG_ROUND_MASK);
486fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		if (tmp != cmd->scan_begin_arg)
487fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			err++;
488fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	}
489fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (cmd->convert_src == TRIG_TIMER) {
490fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		tmp = cmd->convert_arg;
491fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		skel_ns_to_timer(&cmd->convert_arg,
4920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 cmd->flags & TRIG_ROUND_MASK);
493fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		if (tmp != cmd->convert_arg)
494fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			err++;
495fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		if (cmd->scan_begin_src == TRIG_TIMER &&
4960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    cmd->scan_begin_arg <
4970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    cmd->convert_arg * cmd->scan_end_arg) {
498fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			cmd->scan_begin_arg =
4990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    cmd->convert_arg * cmd->scan_end_arg;
500fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef			err++;
501fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		}
502fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	}
503fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
504fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (err)
505fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		return 4;
506fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
507fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	return 0;
508fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef}
509fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
510fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* This function doesn't require a particular form, this is just
511fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * what happens to be used in some of the drivers.  It should
512fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * convert ns nanoseconds to a counter value suitable for programming
513fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the device.  Also, it should adjust ns so that it cooresponds to
514fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * the actual time that the device will use. */
515fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleefstatic int skel_ns_to_timer(unsigned int *ns, int round)
516fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{
517fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* trivial timer */
518fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* if your timing is done through two cascaded timers, the
519fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * i8253_cascade_ns_to_timer() function in 8253.h can be
520fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * very helpful.  There are also i8254_load() and i8254_mm_load()
521fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * which can be used to load values into the ubiquitous 8254 counters
522fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 */
523fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
524fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	return *ns;
525fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef}
526fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
527da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int skel_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
5280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 struct comedi_insn *insn, unsigned int *data)
529fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{
530fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	int i;
531fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	int chan = CR_CHAN(insn->chanspec);
532fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
533588063a10f4e21cd3a2cc693c0c1ebb846ac4ce5Ellwyn Cole	pr_info("skel_ao_winsn\n");
534fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* Writing a list of values to an AO channel is probably not
535fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * very useful, but that's how the interface is defined. */
536fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	for (i = 0; i < insn->n; i++) {
537fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		/* a typical programming sequence */
53897070b32a886d53b7343bcb28ed38d906fa95f50Bill Pemberton		/* outw(data[i],dev->iobase + SKEL_DA0 + chan); */
539fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		devpriv->ao_readback[chan] = data[i];
540fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	}
541fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
542fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* return the number of samples read/written */
543fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	return i;
544fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef}
545fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
546fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* AO subdevices should have a read insn as well as a write insn.
547fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * Usually this means copying a value stored in devpriv. */
548da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int skel_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
5490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 struct comedi_insn *insn, unsigned int *data)
550fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{
551fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	int i;
552fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	int chan = CR_CHAN(insn->chanspec);
553fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
554fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	for (i = 0; i < insn->n; i++)
555fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		data[i] = devpriv->ao_readback[chan];
556fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
557fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	return i;
558fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef}
559fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
560fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef/* DIO devices are slightly special.  Although it is possible to
561fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * implement the insn_read/insn_write interface, it is much more
562fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * useful to applications if you implement the insn_bits interface.
563fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * This allows packed reading/writing of the DIO channels.  The
564fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef * comedi core can convert between insn_bits and insn_read/write */
5650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int skel_dio_insn_bits(struct comedi_device *dev,
5660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			      struct comedi_subdevice *s,
5670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			      struct comedi_insn *insn, unsigned int *data)
568fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{
569fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (insn->n != 2)
570fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		return -EINVAL;
571fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
572fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* The insn data is a mask in data[0] and the new data
573fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * in data[1], each channel cooresponding to a bit. */
574fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	if (data[0]) {
575fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		s->state &= ~data[0];
576fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		s->state |= data[0] & data[1];
577fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		/* Write out the new digital output lines */
57897070b32a886d53b7343bcb28ed38d906fa95f50Bill Pemberton		/* outw(s->state,dev->iobase + SKEL_DIO); */
579fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	}
580fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
581fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* on return, data[1] contains the value of the digital
582fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * input and output lines. */
58397070b32a886d53b7343bcb28ed38d906fa95f50Bill Pemberton	/* data[1]=inw(dev->iobase + SKEL_DIO); */
584fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* or we could just return the software copy of the output values if
585fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * it was a purely digital output subdevice */
58697070b32a886d53b7343bcb28ed38d906fa95f50Bill Pemberton	/* data[1]=s->state; */
587fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
588fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	return 2;
589fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef}
590fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
5910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int skel_dio_insn_config(struct comedi_device *dev,
5920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_subdevice *s,
5930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_insn *insn, unsigned int *data)
594fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef{
595fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	int chan = CR_CHAN(insn->chanspec);
596fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
597fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	/* The input or output configuration of each digital line is
598fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * configured by a special insn_config instruction.  chanspec
599fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * contains the channel to be changed, and data[0] contains the
600fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	 * value COMEDI_INPUT or COMEDI_OUTPUT. */
601fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	switch (data[0]) {
602fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	case INSN_CONFIG_DIO_OUTPUT:
603fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		s->io_bits |= 1 << chan;
604fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		break;
605fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	case INSN_CONFIG_DIO_INPUT:
606fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		s->io_bits &= ~(1 << chan);
607fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		break;
608fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	case INSN_CONFIG_DIO_QUERY:
609fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		data[1] =
6100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
611fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		return insn->n;
612fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		break;
613fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	default:
614fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		return -EINVAL;
615fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef		break;
616fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	}
61797070b32a886d53b7343bcb28ed38d906fa95f50Bill Pemberton	/* outw(s->io_bits,dev->iobase + SKEL_DIO_CONFIG); */
618fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
619fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef	return insn->n;
620fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef}
621fc6a12e5076255c7d0160a6e3749b89c7e4b5bebDavid Schleef
622727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas#ifdef CONFIG_COMEDI_PCI
623727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic int __devinit driver_skel_pci_probe(struct pci_dev *dev,
624727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas					   const struct pci_device_id *ent)
625727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas{
626727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	return comedi_pci_auto_config(dev, driver_skel.driver_name);
627727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas}
628727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
629727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic void __devexit driver_skel_pci_remove(struct pci_dev *dev)
630727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas{
631727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	comedi_pci_auto_unconfig(dev);
632727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas}
633727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
634727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic struct pci_driver driver_skel_pci_driver = {
635727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	.id_table = skel_pci_table,
636727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	.probe = &driver_skel_pci_probe,
637727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	.remove = __devexit_p(&driver_skel_pci_remove)
638727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas};
639727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
640727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic int __init driver_skel_init_module(void)
641727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas{
642727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	int retval;
643727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
644727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	retval = comedi_driver_register(&driver_skel);
645727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	if (retval < 0)
646727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas		return retval;
647727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
648727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	driver_skel_pci_driver.name = (char *)driver_skel.driver_name;
649727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	return pci_register_driver(&driver_skel_pci_driver);
650727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas}
651727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
652727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic void __exit driver_skel_cleanup_module(void)
653727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas{
654727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	pci_unregister_driver(&driver_skel_pci_driver);
655727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	comedi_driver_unregister(&driver_skel);
656727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas}
657727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
658727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasmodule_init(driver_skel_init_module);
659727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasmodule_exit(driver_skel_cleanup_module);
660727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas#else
6617114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic int __init driver_skel_init_module(void)
6627114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
6637114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	return comedi_driver_register(&driver_skel);
6647114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
6657114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
6667114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic void __exit driver_skel_cleanup_module(void)
6677114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
6687114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	comedi_driver_unregister(&driver_skel);
6697114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
6707114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
6717114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_init(driver_skel_init_module);
6727114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_exit(driver_skel_cleanup_module);
673727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas#endif
67490f703d30dd3e0c16ff80f35e34e511385a05ad5Arun Thomas
67590f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_AUTHOR("Comedi http://www.comedi.org");
67690f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_DESCRIPTION("Comedi low-level driver");
67790f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_LICENSE("GPL");
678