pcmmio.c revision 7114a28011f9d5f3d981731ad341177c21f9d948
1/*
2    comedi/drivers/pcmmio.c
3    Driver for Winsystems PC-104 based multifunction IO board.
4
5    COMEDI - Linux Control and Measurement Device Interface
6    Copyright (C) 2007 Calin A. Culianu <calin@ajvar.org>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22/*
23Driver: pcmmio
24Description: A driver for the PCM-MIO multifunction board
25Devices: [Winsystems] PCM-MIO (pcmmio)
26Author: Calin Culianu <calin@ajvar.org>
27Updated: Wed, May 16 2007 16:21:10 -0500
28Status: works
29
30A driver for the relatively new PCM-MIO multifunction board from
31Winsystems.  This board is a PC-104 based I/O board.  It contains
32four subdevices:
33  subdevice 0 - 16 channels of 16-bit AI
34  subdevice 1 - 8 channels of 16-bit AO
35  subdevice 2 - first 24 channels of the 48 channel of DIO
36	(with edge-triggered interrupt support)
37  subdevice 3 - last 24 channels of the 48 channel DIO
38	(no interrupt support for this bank of channels)
39
40  Some notes:
41
42  Synchronous reads and writes are the only things implemented for AI and AO,
43  even though the hardware itself can do streaming acquisition, etc.  Anyone
44  want to add asynchronous I/O for AI/AO as a feature?  Be my guest...
45
46  Asynchronous I/O for the DIO subdevices *is* implemented, however!  They are
47  basically edge-triggered interrupts for any configuration of the first
48  24 DIO-lines.
49
50  Also note that this interrupt support is untested.
51
52  A few words about edge-detection IRQ support (commands on DIO):
53
54  * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ
55    of the board to the comedi_config command.  The board IRQ is not jumpered
56    but rather configured through software, so any IRQ from 1-15 is OK.
57
58  * Due to the genericity of the comedi API, you need to create a special
59    comedi_command in order to use edge-triggered interrupts for DIO.
60
61  * Use comedi_commands with TRIG_NOW.  Your callback will be called each
62    time an edge is detected on the specified DIO line(s), and the data
63    values will be two sample_t's, which should be concatenated to form
64    one 32-bit unsigned int.  This value is the mask of channels that had
65    edges detected from your channel list.  Note that the bits positions
66    in the mask correspond to positions in your chanlist when you
67    specified the command and *not* channel id's!
68
69 *  To set the polarity of the edge-detection interrupts pass a nonzero value
70    for either CR_RANGE or CR_AREF for edge-up polarity, or a zero
71    value for both CR_RANGE and CR_AREF if you want edge-down polarity.
72
73Configuration Options:
74  [0] - I/O port base address
75  [1] - IRQ (optional -- for edge-detect interrupt support only,
76	leave out if you don't need this feature)
77*/
78
79#include <linux/interrupt.h>
80#include <linux/slab.h>
81#include "../comedidev.h"
82#include "pcm_common.h"
83#include <linux/pci.h>		/* for PCI devices */
84
85/* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */
86#define CHANS_PER_PORT   8
87#define PORTS_PER_ASIC   6
88#define INTR_PORTS_PER_ASIC   3
89#define MAX_CHANS_PER_SUBDEV 24	/* number of channels per comedi subdevice */
90#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
91#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
92#define INTR_CHANS_PER_ASIC 24
93#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
94#define MAX_DIO_CHANS   (PORTS_PER_ASIC*1*CHANS_PER_PORT)
95#define MAX_ASICS       (MAX_DIO_CHANS/CHANS_PER_ASIC)
96#define SDEV_NO ((int)(s - dev->subdevices))
97#define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
98/* IO Memory sizes */
99#define ASIC_IOSIZE (0x0B)
100#define PCMMIO48_IOSIZE ASIC_IOSIZE
101
102/* Some offsets - these are all in the 16byte IO memory offset from
103   the base address.  Note that there is a paging scheme to swap out
104   offsets 0x8-0xA using the PAGELOCK register.  See the table below.
105
106  Register(s)       Pages        R/W?        Description
107  --------------------------------------------------------------
108  REG_PORTx         All          R/W         Read/Write/Configure IO
109  REG_INT_PENDING   All          ReadOnly    Quickly see which INT_IDx has int.
110  REG_PAGELOCK      All          WriteOnly   Select a page
111  REG_POLx          Pg. 1 only   WriteOnly   Select edge-detection polarity
112  REG_ENABx         Pg. 2 only   WriteOnly   Enable/Disable edge-detect. int.
113  REG_INT_IDx       Pg. 3 only   R/W         See which ports/bits have ints.
114 */
115#define REG_PORT0 0x0
116#define REG_PORT1 0x1
117#define REG_PORT2 0x2
118#define REG_PORT3 0x3
119#define REG_PORT4 0x4
120#define REG_PORT5 0x5
121#define REG_INT_PENDING 0x6
122#define REG_PAGELOCK 0x7	/*
123				 * page selector register, upper 2 bits select
124				 * a page and bits 0-5 are used to 'lock down'
125				 * a particular port above to make it readonly.
126				 */
127#define REG_POL0 0x8
128#define REG_POL1 0x9
129#define REG_POL2 0xA
130#define REG_ENAB0 0x8
131#define REG_ENAB1 0x9
132#define REG_ENAB2 0xA
133#define REG_INT_ID0 0x8
134#define REG_INT_ID1 0x9
135#define REG_INT_ID2 0xA
136
137#define NUM_PAGED_REGS 3
138#define NUM_PAGES 4
139#define FIRST_PAGED_REG 0x8
140#define REG_PAGE_BITOFFSET 6
141#define REG_LOCK_BITOFFSET 0
142#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
143#define REG_LOCK_MASK (~(REG_PAGE_MASK))
144#define PAGE_POL 1
145#define PAGE_ENAB 2
146#define PAGE_INT_ID 3
147
148typedef int (*comedi_insn_fn_t) (struct comedi_device *,
149				 struct comedi_subdevice *,
150				 struct comedi_insn *, unsigned int *);
151
152static int ai_rinsn(struct comedi_device *, struct comedi_subdevice *,
153		    struct comedi_insn *, unsigned int *);
154static int ao_rinsn(struct comedi_device *, struct comedi_subdevice *,
155		    struct comedi_insn *, unsigned int *);
156static int ao_winsn(struct comedi_device *, struct comedi_subdevice *,
157		    struct comedi_insn *, unsigned int *);
158
159/*
160 * Board descriptions for two imaginary boards.  Describing the
161 * boards in this way is optional, and completely driver-dependent.
162 * Some drivers use arrays such as this, other do not.
163 */
164struct pcmmio_board {
165	const char *name;
166	const int dio_num_asics;
167	const int dio_num_ports;
168	const int total_iosize;
169	const int ai_bits;
170	const int ao_bits;
171	const int n_ai_chans;
172	const int n_ao_chans;
173	const struct comedi_lrange *ai_range_table, *ao_range_table;
174	comedi_insn_fn_t ai_rinsn, ao_rinsn, ao_winsn;
175};
176
177static const struct comedi_lrange ranges_ai = {
178	4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0., 10.)}
179};
180
181static const struct comedi_lrange ranges_ao = {
182	6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.),
183	  RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
184};
185
186static const struct pcmmio_board pcmmio_boards[] = {
187	{
188	 .name = "pcmmio",
189	 .dio_num_asics = 1,
190	 .dio_num_ports = 6,
191	 .total_iosize = 32,
192	 .ai_bits = 16,
193	 .ao_bits = 16,
194	 .n_ai_chans = 16,
195	 .n_ao_chans = 8,
196	 .ai_range_table = &ranges_ai,
197	 .ao_range_table = &ranges_ao,
198	 .ai_rinsn = ai_rinsn,
199	 .ao_rinsn = ao_rinsn,
200	 .ao_winsn = ao_winsn},
201};
202
203/*
204 * Useful for shorthand access to the particular board structure
205 */
206#define thisboard ((const struct pcmmio_board *)dev->board_ptr)
207
208/* this structure is for data unique to this subdevice.  */
209struct pcmmio_subdev_private {
210
211	union {
212		/* for DIO: mapping of halfwords (bytes)
213		   in port/chanarray to iobase */
214		unsigned long iobases[PORTS_PER_SUBDEV];
215
216		/* for AI/AO */
217		unsigned long iobase;
218	};
219	union {
220		struct {
221
222			/* The below is only used for intr subdevices */
223			struct {
224				/*
225				 * if non-negative, this subdev has an
226				 * interrupt asic
227				 */
228				int asic;
229				/*
230				 * if nonnegative, the first channel id for
231				 * interrupts.
232				 */
233				int first_chan;
234				/*
235				 * the number of asic channels in this subdev
236				 * that have interrutps
237				 */
238				int num_asic_chans;
239				/*
240				 * if nonnegative, the first channel id with
241				 * respect to the asic that has interrupts
242				 */
243				int asic_chan;
244				/*
245				 * subdev-relative channel mask for channels
246				 * we are interested in
247				 */
248				int enabled_mask;
249				int active;
250				int stop_count;
251				int continuous;
252				spinlock_t spinlock;
253			} intr;
254		} dio;
255		struct {
256			/* the last unsigned int data written */
257			unsigned int shadow_samples[8];
258		} ao;
259	};
260};
261
262/*
263 * this structure is for data unique to this hardware driver.  If
264 * several hardware drivers keep similar information in this structure,
265 * feel free to suggest moving the variable to the struct comedi_device struct.
266 */
267struct pcmmio_private {
268	/* stuff for DIO */
269	struct {
270		unsigned char pagelock;	/* current page and lock */
271		/* shadow of POLx registers */
272		unsigned char pol[NUM_PAGED_REGS];
273		/* shadow of ENABx registers */
274		unsigned char enab[NUM_PAGED_REGS];
275		int num;
276		unsigned long iobase;
277		unsigned int irq;
278		spinlock_t spinlock;
279	} asics[MAX_ASICS];
280	struct pcmmio_subdev_private *sprivs;
281};
282
283/*
284 * most drivers define the following macro to make it easy to
285 * access the private structure.
286 */
287#define devpriv ((struct pcmmio_private *)dev->private)
288#define subpriv ((struct pcmmio_subdev_private *)s->private)
289/*
290 * The struct comedi_driver structure tells the Comedi core module
291 * which functions to call to configure/deconfigure (attach/detach)
292 * the board, and also about the kernel module that contains
293 * the device code.
294 */
295static int pcmmio_attach(struct comedi_device *dev,
296			 struct comedi_devconfig *it);
297static int pcmmio_detach(struct comedi_device *dev);
298
299static struct comedi_driver driver = {
300	.driver_name = "pcmmio",
301	.module = THIS_MODULE,
302	.attach = pcmmio_attach,
303	.detach = pcmmio_detach,
304/* It is not necessary to implement the following members if you are
305 * writing a driver for a ISA PnP or PCI card */
306	/* Most drivers will support multiple types of boards by
307	 * having an array of board structures.  These were defined
308	 * in pcmmio_boards[] above.  Note that the element 'name'
309	 * was first in the structure -- Comedi uses this fact to
310	 * extract the name of the board without knowing any details
311	 * about the structure except for its length.
312	 * When a device is attached (by comedi_config), the name
313	 * of the device is given to Comedi, and Comedi tries to
314	 * match it by going through the list of board names.  If
315	 * there is a match, the address of the pointer is put
316	 * into dev->board_ptr and driver->attach() is called.
317	 *
318	 * Note that these are not necessary if you can determine
319	 * the type of board in software.  ISA PnP, PCI, and PCMCIA
320	 * devices are such boards.
321	 */
322	.board_name = &pcmmio_boards[0].name,
323	.offset = sizeof(struct pcmmio_board),
324	.num_names = ARRAY_SIZE(pcmmio_boards),
325};
326
327static int pcmmio_dio_insn_bits(struct comedi_device *dev,
328				struct comedi_subdevice *s,
329				struct comedi_insn *insn, unsigned int *data);
330static int pcmmio_dio_insn_config(struct comedi_device *dev,
331				  struct comedi_subdevice *s,
332				  struct comedi_insn *insn, unsigned int *data);
333
334static irqreturn_t interrupt_pcmmio(int irq, void *d);
335static void pcmmio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
336static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
337static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
338static int pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
339			  struct comedi_cmd *cmd);
340
341/* some helper functions to deal with specifics of this device's registers */
342/* sets up/clears ASIC chips to defaults */
343static void init_asics(struct comedi_device *dev);
344static void switch_page(struct comedi_device *dev, int asic, int page);
345#ifdef notused
346static void lock_port(struct comedi_device *dev, int asic, int port);
347static void unlock_port(struct comedi_device *dev, int asic, int port);
348#endif
349
350/*
351 * Attach is called by the Comedi core to configure the driver
352 * for a particular board.  If you specified a board_name array
353 * in the driver structure, dev->board_ptr contains that
354 * address.
355 */
356static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
357{
358	struct comedi_subdevice *s;
359	int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
360	    thisasic_chanct = 0;
361	unsigned long iobase;
362	unsigned int irq[MAX_ASICS];
363
364	iobase = it->options[0];
365	irq[0] = it->options[1];
366
367	printk("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name,
368	       iobase);
369
370	dev->iobase = iobase;
371
372	if (!iobase || !request_region(iobase,
373				       thisboard->total_iosize,
374				       driver.driver_name)) {
375		printk("I/O port conflict\n");
376		return -EIO;
377	}
378
379/*
380 * Initialize dev->board_name.  Note that we can use the "thisboard"
381 * macro now, since we just initialized it in the last line.
382 */
383	dev->board_name = thisboard->name;
384
385/*
386 * Allocate the private structure area.  alloc_private() is a
387 * convenient macro defined in comedidev.h.
388 */
389	if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
390		printk("cannot allocate private data structure\n");
391		return -ENOMEM;
392	}
393
394	for (asic = 0; asic < MAX_ASICS; ++asic) {
395		devpriv->asics[asic].num = asic;
396		devpriv->asics[asic].iobase =
397		    dev->iobase + 16 + asic * ASIC_IOSIZE;
398		/*
399		 * this gets actually set at the end of this function when we
400		 * request_irqs
401		 */
402		devpriv->asics[asic].irq = 0;
403		spin_lock_init(&devpriv->asics[asic].spinlock);
404	}
405
406	chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
407	n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
408	n_subdevs = n_dio_subdevs + 2;
409	devpriv->sprivs =
410	    kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
411		    GFP_KERNEL);
412	if (!devpriv->sprivs) {
413		printk("cannot allocate subdevice private data structures\n");
414		return -ENOMEM;
415	}
416	/*
417	 * Allocate the subdevice structures.  alloc_subdevice() is a
418	 * convenient macro defined in comedidev.h.
419	 *
420	 * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
421	 */
422	if (alloc_subdevices(dev, n_subdevs) < 0) {
423		printk("cannot allocate subdevice data structures\n");
424		return -ENOMEM;
425	}
426
427	/* First, AI */
428	sdev_no = 0;
429	s = dev->subdevices + sdev_no;
430	s->private = devpriv->sprivs + sdev_no;
431	s->maxdata = (1 << thisboard->ai_bits) - 1;
432	s->range_table = thisboard->ai_range_table;
433	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
434	s->type = COMEDI_SUBD_AI;
435	s->n_chan = thisboard->n_ai_chans;
436	s->len_chanlist = s->n_chan;
437	s->insn_read = thisboard->ai_rinsn;
438	subpriv->iobase = dev->iobase + 0;
439	/* initialize the resource enable register by clearing it */
440	outb(0, subpriv->iobase + 3);
441	outb(0, subpriv->iobase + 4 + 3);
442
443	/* Next, AO */
444	++sdev_no;
445	s = dev->subdevices + sdev_no;
446	s->private = devpriv->sprivs + sdev_no;
447	s->maxdata = (1 << thisboard->ao_bits) - 1;
448	s->range_table = thisboard->ao_range_table;
449	s->subdev_flags = SDF_READABLE;
450	s->type = COMEDI_SUBD_AO;
451	s->n_chan = thisboard->n_ao_chans;
452	s->len_chanlist = s->n_chan;
453	s->insn_read = thisboard->ao_rinsn;
454	s->insn_write = thisboard->ao_winsn;
455	subpriv->iobase = dev->iobase + 8;
456	/* initialize the resource enable register by clearing it */
457	outb(0, subpriv->iobase + 3);
458	outb(0, subpriv->iobase + 4 + 3);
459
460	++sdev_no;
461	port = 0;
462	asic = 0;
463	for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
464		int byte_no;
465
466		s = dev->subdevices + sdev_no;
467		s->private = devpriv->sprivs + sdev_no;
468		s->maxdata = 1;
469		s->range_table = &range_digital;
470		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
471		s->type = COMEDI_SUBD_DIO;
472		s->insn_bits = pcmmio_dio_insn_bits;
473		s->insn_config = pcmmio_dio_insn_config;
474		s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
475		subpriv->dio.intr.asic = -1;
476		subpriv->dio.intr.first_chan = -1;
477		subpriv->dio.intr.asic_chan = -1;
478		subpriv->dio.intr.num_asic_chans = -1;
479		subpriv->dio.intr.active = 0;
480		s->len_chanlist = 1;
481
482		/* save the ioport address for each 'port' of 8 channels in the
483		   subdevice */
484		for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
485			if (port >= PORTS_PER_ASIC) {
486				port = 0;
487				++asic;
488				thisasic_chanct = 0;
489			}
490			subpriv->iobases[byte_no] =
491			    devpriv->asics[asic].iobase + port;
492
493			if (thisasic_chanct <
494			    CHANS_PER_PORT * INTR_PORTS_PER_ASIC
495			    && subpriv->dio.intr.asic < 0) {
496				/*
497				 * this is an interrupt subdevice,
498				 * so setup the struct
499				 */
500				subpriv->dio.intr.asic = asic;
501				subpriv->dio.intr.active = 0;
502				subpriv->dio.intr.stop_count = 0;
503				subpriv->dio.intr.first_chan = byte_no * 8;
504				subpriv->dio.intr.asic_chan = thisasic_chanct;
505				subpriv->dio.intr.num_asic_chans =
506				    s->n_chan - subpriv->dio.intr.first_chan;
507				s->cancel = pcmmio_cancel;
508				s->do_cmd = pcmmio_cmd;
509				s->do_cmdtest = pcmmio_cmdtest;
510				s->len_chanlist =
511				    subpriv->dio.intr.num_asic_chans;
512			}
513			thisasic_chanct += CHANS_PER_PORT;
514		}
515		spin_lock_init(&subpriv->dio.intr.spinlock);
516
517		chans_left -= s->n_chan;
518
519		if (!chans_left) {
520			/*
521			 * reset the asic to our first asic,
522			 * to do intr subdevs
523			 */
524			asic = 0;
525			port = 0;
526		}
527
528	}
529
530	init_asics(dev);	/* clear out all the registers, basically */
531
532	for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
533		if (irq[asic]
534		    && request_irq(irq[asic], interrupt_pcmmio,
535				   IRQF_SHARED, thisboard->name, dev)) {
536			int i;
537			/* unroll the allocated irqs.. */
538			for (i = asic - 1; i >= 0; --i) {
539				free_irq(irq[i], dev);
540				devpriv->asics[i].irq = irq[i] = 0;
541			}
542			irq[asic] = 0;
543		}
544		devpriv->asics[asic].irq = irq[asic];
545	}
546
547	dev->irq = irq[0];	/*
548				 * grr.. wish comedi dev struct supported
549				 * multiple irqs..
550				 */
551
552	if (irq[0]) {
553		printk("irq: %u ", irq[0]);
554		if (thisboard->dio_num_asics == 2 && irq[1])
555			printk("second ASIC irq: %u ", irq[1]);
556	} else {
557		printk("(IRQ mode disabled) ");
558	}
559
560	printk("attached\n");
561
562	return 1;
563}
564
565/*
566 * _detach is called to deconfigure a device.  It should deallocate
567 * resources.
568 * This function is also called when _attach() fails, so it should be
569 * careful not to release resources that were not necessarily
570 * allocated by _attach().  dev->private and dev->subdevices are
571 * deallocated automatically by the core.
572 */
573static int pcmmio_detach(struct comedi_device *dev)
574{
575	int i;
576
577	printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name);
578	if (dev->iobase)
579		release_region(dev->iobase, thisboard->total_iosize);
580
581	for (i = 0; i < MAX_ASICS; ++i) {
582		if (devpriv && devpriv->asics[i].irq)
583			free_irq(devpriv->asics[i].irq, dev);
584	}
585
586	if (devpriv && devpriv->sprivs)
587		kfree(devpriv->sprivs);
588
589	return 0;
590}
591
592/* DIO devices are slightly special.  Although it is possible to
593 * implement the insn_read/insn_write interface, it is much more
594 * useful to applications if you implement the insn_bits interface.
595 * This allows packed reading/writing of the DIO channels.  The
596 * comedi core can convert between insn_bits and insn_read/write */
597static int pcmmio_dio_insn_bits(struct comedi_device *dev,
598				struct comedi_subdevice *s,
599				struct comedi_insn *insn, unsigned int *data)
600{
601	int byte_no;
602	if (insn->n != 2)
603		return -EINVAL;
604
605	/* NOTE:
606	   reading a 0 means this channel was high
607	   writine a 0 sets the channel high
608	   reading a 1 means this channel was low
609	   writing a 1 means set this channel low
610
611	   Therefore everything is always inverted. */
612
613	/* The insn data is a mask in data[0] and the new data
614	 * in data[1], each channel cooresponding to a bit. */
615
616#ifdef DAMMIT_ITS_BROKEN
617	/* DEBUG */
618	printk("write mask: %08x  data: %08x\n", data[0], data[1]);
619#endif
620
621	s->state = 0;
622
623	for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
624		/* address of 8-bit port */
625		unsigned long ioaddr = subpriv->iobases[byte_no],
626		    /* bit offset of port in 32-bit doubleword */
627		    offset = byte_no * 8;
628		/* this 8-bit port's data */
629		unsigned char byte = 0,
630		    /* The write mask for this port (if any) */
631		    write_mask_byte = (data[0] >> offset) & 0xff,
632		    /* The data byte for this port */
633		    data_byte = (data[1] >> offset) & 0xff;
634
635		byte = inb(ioaddr);	/* read all 8-bits for this port */
636
637#ifdef DAMMIT_ITS_BROKEN
638		/* DEBUG */
639		printk
640		    ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ",
641		     byte_no, (unsigned)write_mask_byte, (unsigned)data_byte,
642		     offset, ioaddr, (unsigned)byte);
643#endif
644
645		if (write_mask_byte) {
646			/*
647			 * this byte has some write_bits
648			 * -- so set the output lines
649			 */
650			/* clear bits for write mask */
651			byte &= ~write_mask_byte;
652			/* set to inverted data_byte */
653			byte |= ~data_byte & write_mask_byte;
654			/* Write out the new digital output state */
655			outb(byte, ioaddr);
656		}
657#ifdef DAMMIT_ITS_BROKEN
658		/* DEBUG */
659		printk("data_out_byte %02x\n", (unsigned)byte);
660#endif
661		/* save the digital input lines for this byte.. */
662		s->state |= ((unsigned int)byte) << offset;
663	}
664
665	/* now return the DIO lines to data[1] - note they came inverted! */
666	data[1] = ~s->state;
667
668#ifdef DAMMIT_ITS_BROKEN
669	/* DEBUG */
670	printk("s->state %08x data_out %08x\n", s->state, data[1]);
671#endif
672
673	return 2;
674}
675
676/* The input or output configuration of each digital line is
677 * configured by a special insn_config instruction.  chanspec
678 * contains the channel to be changed, and data[0] contains the
679 * value COMEDI_INPUT or COMEDI_OUTPUT. */
680static int pcmmio_dio_insn_config(struct comedi_device *dev,
681				  struct comedi_subdevice *s,
682				  struct comedi_insn *insn, unsigned int *data)
683{
684	int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
685	    chan % 8;
686	unsigned long ioaddr;
687	unsigned char byte;
688
689	/* Compute ioaddr for this channel */
690	ioaddr = subpriv->iobases[byte_no];
691
692	/* NOTE:
693	   writing a 0 an IO channel's bit sets the channel to INPUT
694	   and pulls the line high as well
695
696	   writing a 1 to an IO channel's  bit pulls the line low
697
698	   All channels are implicitly always in OUTPUT mode -- but when
699	   they are high they can be considered to be in INPUT mode..
700
701	   Thus, we only force channels low if the config request was INPUT,
702	   otherwise we do nothing to the hardware.    */
703
704	switch (data[0]) {
705	case INSN_CONFIG_DIO_OUTPUT:
706		/* save to io_bits -- don't actually do anything since
707		   all input channels are also output channels... */
708		s->io_bits |= 1 << chan;
709		break;
710	case INSN_CONFIG_DIO_INPUT:
711		/* write a 0 to the actual register representing the channel
712		   to set it to 'input'.  0 means "float high". */
713		byte = inb(ioaddr);
714		byte &= ~(1 << bit_no);
715				/**< set input channel to '0' */
716
717		/*
718		 * write out byte -- this is the only time we actually affect
719		 * the hardware as all channels are implicitly output
720		 * -- but input channels are set to float-high
721		 */
722		outb(byte, ioaddr);
723
724		/* save to io_bits */
725		s->io_bits &= ~(1 << chan);
726		break;
727
728	case INSN_CONFIG_DIO_QUERY:
729		/* retreive from shadow register */
730		data[1] =
731		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
732		return insn->n;
733		break;
734
735	default:
736		return -EINVAL;
737		break;
738	}
739
740	return insn->n;
741}
742
743static void init_asics(struct comedi_device *dev)
744{				/* sets up an
745				   ASIC chip to defaults */
746	int asic;
747
748	for (asic = 0; asic < thisboard->dio_num_asics; ++asic) {
749		int port, page;
750		unsigned long baseaddr = devpriv->asics[asic].iobase;
751
752		switch_page(dev, asic, 0);	/* switch back to page 0 */
753
754		/* first, clear all the DIO port bits */
755		for (port = 0; port < PORTS_PER_ASIC; ++port)
756			outb(0, baseaddr + REG_PORT0 + port);
757
758		/* Next, clear all the paged registers for each page */
759		for (page = 1; page < NUM_PAGES; ++page) {
760			int reg;
761			/* now clear all the paged registers */
762			switch_page(dev, asic, page);
763			for (reg = FIRST_PAGED_REG;
764			     reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
765				outb(0, baseaddr + reg);
766		}
767
768		/* DEBUG  set rising edge interrupts on port0 of both asics */
769		/*switch_page(dev, asic, PAGE_POL);
770		   outb(0xff, baseaddr + REG_POL0);
771		   switch_page(dev, asic, PAGE_ENAB);
772		   outb(0xff, baseaddr + REG_ENAB0); */
773		/* END DEBUG */
774
775		/* switch back to default page 0 */
776		switch_page(dev, asic, 0);
777	}
778}
779
780static void switch_page(struct comedi_device *dev, int asic, int page)
781{
782	if (asic < 0 || asic >= thisboard->dio_num_asics)
783		return;		/* paranoia */
784	if (page < 0 || page >= NUM_PAGES)
785		return;		/* more paranoia */
786
787	devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
788	devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
789
790	/* now write out the shadow register */
791	outb(devpriv->asics[asic].pagelock,
792	     devpriv->asics[asic].iobase + REG_PAGELOCK);
793}
794
795#ifdef notused
796static void lock_port(struct comedi_device *dev, int asic, int port)
797{
798	if (asic < 0 || asic >= thisboard->dio_num_asics)
799		return;		/* paranoia */
800	if (port < 0 || port >= PORTS_PER_ASIC)
801		return;		/* more paranoia */
802
803	devpriv->asics[asic].pagelock |= 0x1 << port;
804	/* now write out the shadow register */
805	outb(devpriv->asics[asic].pagelock,
806	     devpriv->asics[asic].iobase + REG_PAGELOCK);
807	return;
808}
809
810static void unlock_port(struct comedi_device *dev, int asic, int port)
811{
812	if (asic < 0 || asic >= thisboard->dio_num_asics)
813		return;		/* paranoia */
814	if (port < 0 || port >= PORTS_PER_ASIC)
815		return;		/* more paranoia */
816	devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
817	/* now write out the shadow register */
818	outb(devpriv->asics[asic].pagelock,
819	     devpriv->asics[asic].iobase + REG_PAGELOCK);
820}
821#endif /* notused */
822
823static irqreturn_t interrupt_pcmmio(int irq, void *d)
824{
825	int asic, got1 = 0;
826	struct comedi_device *dev = (struct comedi_device *)d;
827
828	for (asic = 0; asic < MAX_ASICS; ++asic) {
829		if (irq == devpriv->asics[asic].irq) {
830			unsigned long flags;
831			unsigned triggered = 0;
832			unsigned long iobase = devpriv->asics[asic].iobase;
833			/* it is an interrupt for ASIC #asic */
834			unsigned char int_pend;
835
836			spin_lock_irqsave(&devpriv->asics[asic].spinlock,
837					  flags);
838
839			int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
840
841			if (int_pend) {
842				int port;
843				for (port = 0; port < INTR_PORTS_PER_ASIC;
844				     ++port) {
845					if (int_pend & (0x1 << port)) {
846						unsigned char
847						    io_lines_with_edges = 0;
848						switch_page(dev, asic,
849							    PAGE_INT_ID);
850						io_lines_with_edges =
851						    inb(iobase +
852							REG_INT_ID0 + port);
853
854						if (io_lines_with_edges)
855							/*
856							 * clear pending
857							 * interrupt
858							 */
859							outb(0, iobase +
860							     REG_INT_ID0 +
861							     port);
862
863						triggered |=
864						    io_lines_with_edges <<
865						    port * 8;
866					}
867				}
868
869				++got1;
870			}
871
872			spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
873					       flags);
874
875			if (triggered) {
876				struct comedi_subdevice *s;
877				/*
878				 * TODO here: dispatch io lines to subdevs
879				 * with commands..
880				 */
881				printk
882				    ("PCMMIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n",
883				     irq, asic, triggered);
884				for (s = dev->subdevices + 2;
885				     s < dev->subdevices + dev->n_subdevices;
886				     ++s) {
887					/*
888					 * this is an interrupt subdev,
889					 * and it matches this asic!
890					 */
891					if (subpriv->dio.intr.asic == asic) {
892						unsigned long flags;
893						unsigned oldevents;
894
895						spin_lock_irqsave(&subpriv->dio.
896								  intr.spinlock,
897								  flags);
898
899						oldevents = s->async->events;
900
901						if (subpriv->dio.intr.active) {
902							unsigned mytrig =
903							    ((triggered >>
904							      subpriv->dio.intr.asic_chan)
905							     &
906							     ((0x1 << subpriv->
907							       dio.intr.
908							       num_asic_chans) -
909							      1)) << subpriv->
910							    dio.intr.first_chan;
911							if (mytrig &
912							    subpriv->dio.
913							    intr.enabled_mask) {
914								unsigned int val
915								    = 0;
916								unsigned int n,
917								    ch, len;
918
919								len =
920								    s->
921								    async->cmd.chanlist_len;
922								for (n = 0;
923								     n < len;
924								     n++) {
925									ch = CR_CHAN(s->async->cmd.chanlist[n]);
926									if (mytrig & (1U << ch))
927										val |= (1U << n);
928								}
929								/* Write the scan to the buffer. */
930								if (comedi_buf_put(s->async, ((short *)&val)[0])
931								    &&
932								    comedi_buf_put
933								    (s->async,
934								     ((short *)
935								      &val)[1])) {
936									s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
937								} else {
938									/* Overflow! Stop acquisition!! */
939									/* TODO: STOP_ACQUISITION_CALL_HERE!! */
940									pcmmio_stop_intr
941									    (dev,
942									     s);
943								}
944
945								/* Check for end of acquisition. */
946								if (!subpriv->dio.intr.continuous) {
947									/* stop_src == TRIG_COUNT */
948									if (subpriv->dio.intr.stop_count > 0) {
949										subpriv->dio.intr.stop_count--;
950										if (subpriv->dio.intr.stop_count == 0) {
951											s->async->events |= COMEDI_CB_EOA;
952											/* TODO: STOP_ACQUISITION_CALL_HERE!! */
953											pcmmio_stop_intr
954											    (dev,
955											     s);
956										}
957									}
958								}
959							}
960						}
961
962						spin_unlock_irqrestore
963						    (&subpriv->dio.intr.
964						     spinlock, flags);
965
966						if (oldevents !=
967						    s->async->events) {
968							comedi_event(dev, s);
969						}
970
971					}
972
973				}
974			}
975
976		}
977	}
978	if (!got1)
979		return IRQ_NONE;	/* interrupt from other source */
980	return IRQ_HANDLED;
981}
982
983static void pcmmio_stop_intr(struct comedi_device *dev,
984			     struct comedi_subdevice *s)
985{
986	int nports, firstport, asic, port;
987
988	asic = subpriv->dio.intr.asic;
989	if (asic < 0)
990		return;		/* not an interrupt subdev */
991
992	subpriv->dio.intr.enabled_mask = 0;
993	subpriv->dio.intr.active = 0;
994	s->async->inttrig = 0;
995	nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
996	firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
997	switch_page(dev, asic, PAGE_ENAB);
998	for (port = firstport; port < firstport + nports; ++port) {
999		/* disable all intrs for this subdev.. */
1000		outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
1001	}
1002}
1003
1004static int pcmmio_start_intr(struct comedi_device *dev,
1005			     struct comedi_subdevice *s)
1006{
1007	if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) {
1008		/* An empty acquisition! */
1009		s->async->events |= COMEDI_CB_EOA;
1010		subpriv->dio.intr.active = 0;
1011		return 1;
1012	} else {
1013		unsigned bits = 0, pol_bits = 0, n;
1014		int nports, firstport, asic, port;
1015		struct comedi_cmd *cmd = &s->async->cmd;
1016
1017		asic = subpriv->dio.intr.asic;
1018		if (asic < 0)
1019			return 1;	/* not an interrupt
1020					   subdev */
1021		subpriv->dio.intr.enabled_mask = 0;
1022		subpriv->dio.intr.active = 1;
1023		nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
1024		firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
1025		if (cmd->chanlist) {
1026			for (n = 0; n < cmd->chanlist_len; n++) {
1027				bits |= (1U << CR_CHAN(cmd->chanlist[n]));
1028				pol_bits |= (CR_AREF(cmd->chanlist[n])
1029					     || CR_RANGE(cmd->
1030							 chanlist[n]) ? 1U : 0U)
1031				    << CR_CHAN(cmd->chanlist[n]);
1032			}
1033		}
1034		bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) -
1035			 1) << subpriv->dio.intr.first_chan;
1036		subpriv->dio.intr.enabled_mask = bits;
1037
1038		{
1039			/*
1040			 * the below code configures the board
1041			 * to use a specific IRQ from 0-15.
1042			 */
1043			unsigned char b;
1044			/*
1045			 * set resource enable register
1046			 * to enable IRQ operation
1047			 */
1048			outb(1 << 4, dev->iobase + 3);
1049			/* set bits 0-3 of b to the irq number from 0-15 */
1050			b = dev->irq & ((1 << 4) - 1);
1051			outb(b, dev->iobase + 2);
1052			/* done, we told the board what irq to use */
1053		}
1054
1055		switch_page(dev, asic, PAGE_ENAB);
1056		for (port = firstport; port < firstport + nports; ++port) {
1057			unsigned enab =
1058			    bits >> (subpriv->dio.intr.first_chan + (port -
1059								     firstport)
1060				     * 8) & 0xff, pol =
1061			    pol_bits >> (subpriv->dio.intr.first_chan +
1062					 (port - firstport) * 8) & 0xff;
1063			/* set enab intrs for this subdev.. */
1064			outb(enab,
1065			     devpriv->asics[asic].iobase + REG_ENAB0 + port);
1066			switch_page(dev, asic, PAGE_POL);
1067			outb(pol,
1068			     devpriv->asics[asic].iobase + REG_ENAB0 + port);
1069		}
1070	}
1071	return 0;
1072}
1073
1074static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1075{
1076	unsigned long flags;
1077
1078	spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1079	if (subpriv->dio.intr.active)
1080		pcmmio_stop_intr(dev, s);
1081	spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1082
1083	return 0;
1084}
1085
1086/*
1087 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
1088 */
1089static int
1090pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
1091			  unsigned int trignum)
1092{
1093	unsigned long flags;
1094	int event = 0;
1095
1096	if (trignum != 0)
1097		return -EINVAL;
1098
1099	spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1100	s->async->inttrig = 0;
1101	if (subpriv->dio.intr.active)
1102		event = pcmmio_start_intr(dev, s);
1103	spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1104
1105	if (event)
1106		comedi_event(dev, s);
1107
1108	return 1;
1109}
1110
1111/*
1112 * 'do_cmd' function for an 'INTERRUPT' subdevice.
1113 */
1114static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1115{
1116	struct comedi_cmd *cmd = &s->async->cmd;
1117	unsigned long flags;
1118	int event = 0;
1119
1120	spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1121	subpriv->dio.intr.active = 1;
1122
1123	/* Set up end of acquisition. */
1124	switch (cmd->stop_src) {
1125	case TRIG_COUNT:
1126		subpriv->dio.intr.continuous = 0;
1127		subpriv->dio.intr.stop_count = cmd->stop_arg;
1128		break;
1129	default:
1130		/* TRIG_NONE */
1131		subpriv->dio.intr.continuous = 1;
1132		subpriv->dio.intr.stop_count = 0;
1133		break;
1134	}
1135
1136	/* Set up start of acquisition. */
1137	switch (cmd->start_src) {
1138	case TRIG_INT:
1139		s->async->inttrig = pcmmio_inttrig_start_intr;
1140		break;
1141	default:
1142		/* TRIG_NOW */
1143		event = pcmmio_start_intr(dev, s);
1144		break;
1145	}
1146	spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1147
1148	if (event)
1149		comedi_event(dev, s);
1150
1151	return 0;
1152}
1153
1154static int
1155pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
1156	       struct comedi_cmd *cmd)
1157{
1158	return comedi_pcm_cmdtest(dev, s, cmd);
1159}
1160
1161static int adc_wait_ready(unsigned long iobase)
1162{
1163	unsigned long retry = 100000;
1164	while (retry--)
1165		if (inb(iobase + 3) & 0x80)
1166			return 0;
1167	return 1;
1168}
1169
1170/* All this is for AI and AO */
1171static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1172		    struct comedi_insn *insn, unsigned int *data)
1173{
1174	int n;
1175	unsigned long iobase = subpriv->iobase;
1176
1177	/*
1178	   1. write the CMD byte (to BASE+2)
1179	   2. read junk lo byte (BASE+0)
1180	   3. read junk hi byte (BASE+1)
1181	   4. (mux settled so) write CMD byte again (BASE+2)
1182	   5. read valid lo byte(BASE+0)
1183	   6. read valid hi byte(BASE+1)
1184
1185	   Additionally note that the BASE += 4 if the channel >= 8
1186	 */
1187
1188	/* convert n samples */
1189	for (n = 0; n < insn->n; n++) {
1190		unsigned chan = CR_CHAN(insn->chanspec), range =
1191		    CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec);
1192		unsigned char command_byte = 0;
1193		unsigned iooffset = 0;
1194		short sample, adc_adjust = 0;
1195
1196		if (chan > 7)
1197			chan -= 8, iooffset = 4;	/*
1198							 * use the second dword
1199							 * for channels > 7
1200							 */
1201
1202		if (aref != AREF_DIFF) {
1203			aref = AREF_GROUND;
1204			command_byte |= 1 << 7;	/*
1205						 * set bit 7 to indicate
1206						 * single-ended
1207						 */
1208		}
1209		if (range < 2)
1210			adc_adjust = 0x8000;	/*
1211						 * bipolar ranges
1212						 * (-5,5 .. -10,10 need to be
1213						 * adjusted -- that is.. they
1214						 * need to wrap around by
1215						 * adding 0x8000
1216						 */
1217
1218		if (chan % 2) {
1219			command_byte |= 1 << 6;	/*
1220						 * odd-numbered channels
1221						 * have bit 6 set
1222						 */
1223		}
1224
1225		/* select the channel, bits 4-5 == chan/2 */
1226		command_byte |= ((chan / 2) & 0x3) << 4;
1227
1228		/* set the range, bits 2-3 */
1229		command_byte |= (range & 0x3) << 2;
1230
1231		/* need to do this twice to make sure mux settled */
1232		/* chan/range/aref select */
1233		outb(command_byte, iobase + iooffset + 2);
1234
1235		/* wait for the adc to say it finised the conversion */
1236		adc_wait_ready(iobase + iooffset);
1237
1238		/* select the chan/range/aref AGAIN */
1239		outb(command_byte, iobase + iooffset + 2);
1240
1241		adc_wait_ready(iobase + iooffset);
1242
1243		/* read data lo byte */
1244		sample = inb(iobase + iooffset + 0);
1245
1246		/* read data hi byte */
1247		sample |= inb(iobase + iooffset + 1) << 8;
1248		sample += adc_adjust;	/* adjustment .. munge data */
1249		data[n] = sample;
1250	}
1251	/* return the number of samples read/written */
1252	return n;
1253}
1254
1255static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1256		    struct comedi_insn *insn, unsigned int *data)
1257{
1258	int n;
1259	for (n = 0; n < insn->n; n++) {
1260		unsigned chan = CR_CHAN(insn->chanspec);
1261		if (chan < s->n_chan)
1262			data[n] = subpriv->ao.shadow_samples[chan];
1263	}
1264	return n;
1265}
1266
1267static int wait_dac_ready(unsigned long iobase)
1268{
1269	unsigned long retry = 100000L;
1270
1271	/* This may seem like an absurd way to handle waiting and violates the
1272	   "no busy waiting" policy. The fact is that the hardware is
1273	   normally so fast that we usually only need one time through the loop
1274	   anyway. The longer timeout is for rare occasions and for detecting
1275	   non-existant hardware.  */
1276
1277	while (retry--) {
1278		if (inb(iobase + 3) & 0x80)
1279			return 0;
1280
1281	}
1282	return 1;
1283}
1284
1285static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
1286		    struct comedi_insn *insn, unsigned int *data)
1287{
1288	int n;
1289	unsigned iobase = subpriv->iobase, iooffset = 0;
1290
1291	for (n = 0; n < insn->n; n++) {
1292		unsigned chan = CR_CHAN(insn->chanspec), range =
1293		    CR_RANGE(insn->chanspec);
1294		if (chan < s->n_chan) {
1295			unsigned char command_byte = 0, range_byte =
1296			    range & ((1 << 4) - 1);
1297			if (chan >= 4)
1298				chan -= 4, iooffset += 4;
1299			/* set the range.. */
1300			outb(range_byte, iobase + iooffset + 0);
1301			outb(0, iobase + iooffset + 1);
1302
1303			/* tell it to begin */
1304			command_byte = (chan << 1) | 0x60;
1305			outb(command_byte, iobase + iooffset + 2);
1306
1307			wait_dac_ready(iobase + iooffset);
1308
1309			/* low order byte */
1310			outb(data[n] & 0xff, iobase + iooffset + 0);
1311
1312			/* high order byte */
1313			outb((data[n] >> 8) & 0xff, iobase + iooffset + 1);
1314
1315			/*
1316			 * set bit 4 of command byte to indicate
1317			 * data is loaded and trigger conversion
1318			 */
1319			command_byte = 0x70 | (chan << 1);
1320			/* trigger converion */
1321			outb(command_byte, iobase + iooffset + 2);
1322
1323			wait_dac_ready(iobase + iooffset);
1324
1325			/* save to shadow register for ao_rinsn */
1326			subpriv->ao.shadow_samples[chan] = data[n];
1327		}
1328	}
1329	return n;
1330}
1331
1332/*
1333 * A convenient macro that defines init_module() and cleanup_module(),
1334 * as necessary.
1335 */
1336static int __init driver_init_module(void)
1337{
1338	return comedi_driver_register(&driver);
1339}
1340
1341static void __exit driver_cleanup_module(void)
1342{
1343	comedi_driver_unregister(&driver);
1344}
1345
1346module_init(driver_init_module);
1347module_exit(driver_cleanup_module);
1348
1349MODULE_AUTHOR("Comedi http://www.comedi.org");
1350MODULE_DESCRIPTION("Comedi low-level driver");
1351MODULE_LICENSE("GPL");
1352