118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/*
218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel    comedi/drivers/ssv_dnp.c
318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel    generic comedi driver for SSV Embedded Systems' DIL/Net-PCs
418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel    Copyright (C) 2001 Robert Schwebel <robert@schwebel.de>
518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel    COMEDI - Linux Control and Measurement Device Interface
718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel    Copyright (C) 2000 David A. Schleef <ds@schleef.org>
818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel    This program is free software; you can redistribute it and/or modify
1018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel    it under the terms of the GNU General Public License as published by
1118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel    the Free Software Foundation; either version 2 of the License, or
1218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel    (at your option) any later version.
1318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
1418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel    This program is distributed in the hope that it will be useful,
1518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel    but WITHOUT ANY WARRANTY; without even the implied warranty of
1618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel    GNU General Public License for more details.
1818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
1918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel    You should have received a copy of the GNU General Public License
2018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel    along with this program; if not, write to the Free Software
2118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
2218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
2318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel*/
2418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/*
2518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert SchwebelDriver: ssv_dnp
2618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert SchwebelDescription: SSV Embedded Systems DIL/Net-PC
2718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert SchwebelAuthor: Robert Schwebel <robert@schwebel.de>
2818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert SchwebelDevices: [SSV Embedded Systems] DIL/Net-PC 1486 (dnp-1486)
2918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert SchwebelStatus: unknown
3018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel*/
3118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
3218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* include files ----------------------------------------------------------- */
3318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
3418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel#include "../comedidev.h"
3518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
3618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* Some global definitions: the registers of the DNP ----------------------- */
3718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/*                                                                           */
3818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* For port A and B the mode register has bits corresponding to the output   */
3918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* pins, where Bit-N = 0 -> input, Bit-N = 1 -> output. Note that bits       */
4018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* 4 to 7 correspond to pin 0..3 for port C data register. Ensure that bits  */
4118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* 0..3 remain unchanged! For details about Port C Mode Register see         */
4218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* the remarks in dnp_insn_config() below.                                   */
4318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
4406033fced289985294e5a3f694646014d80b48ccDarren Armstrong#define CSCIR 0x22		/* Chip Setup and Control Index Register     */
4506033fced289985294e5a3f694646014d80b48ccDarren Armstrong#define CSCDR 0x23		/* Chip Setup and Control Data Register      */
4606033fced289985294e5a3f694646014d80b48ccDarren Armstrong#define PAMR  0xa5		/* Port A Mode Register                      */
4706033fced289985294e5a3f694646014d80b48ccDarren Armstrong#define PADR  0xa9		/* Port A Data Register                      */
4806033fced289985294e5a3f694646014d80b48ccDarren Armstrong#define PBMR  0xa4		/* Port B Mode Register                      */
4906033fced289985294e5a3f694646014d80b48ccDarren Armstrong#define PBDR  0xa8		/* Port B Data Register                      */
5006033fced289985294e5a3f694646014d80b48ccDarren Armstrong#define PCMR  0xa3		/* Port C Mode Register                      */
5106033fced289985294e5a3f694646014d80b48ccDarren Armstrong#define PCDR  0xa7		/* Port C Data Register                      */
5218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
5318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* This data structure holds information about the supported boards -------- */
5418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
55c0d1482252b9b87c62b8d0ddb7ceecc369c6e34eBill Pembertonstruct dnp_board {
5618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	const char *name;
5718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	int ai_chans;
5818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	int ai_bits;
5918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	int have_dio;
60c0d1482252b9b87c62b8d0ddb7ceecc369c6e34eBill Pemberton};
6118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
6206033fced289985294e5a3f694646014d80b48ccDarren Armstrong/* We only support one DNP 'board' variant at the moment */
6306033fced289985294e5a3f694646014d80b48ccDarren Armstrongstatic const struct dnp_board dnp_boards[] = {
6406033fced289985294e5a3f694646014d80b48ccDarren Armstrong{
650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .name = "dnp-1486",
660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_chans = 16,
670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_bits = 12,
680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .have_dio = 1,
690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
7018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel};
7118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
7218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* Useful for shorthand access to the particular board structure ----------- */
73c0d1482252b9b87c62b8d0ddb7ceecc369c6e34eBill Pemberton#define thisboard ((const struct dnp_board *)dev->board_ptr)
7418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
7518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* This structure is for data unique to the DNP driver --------------------- */
768532530040c05ab60e7d83c705713ef2629cd3bbBill Pembertonstruct dnp_private_data {
778532530040c05ab60e7d83c705713ef2629cd3bbBill Pemberton
788532530040c05ab60e7d83c705713ef2629cd3bbBill Pemberton};
798532530040c05ab60e7d83c705713ef2629cd3bbBill Pemberton
8018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* Shorthand macro for faster access to the private data ------------------- */
8118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel#define devpriv ((dnp_private *)dev->private)
8218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
8318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* ------------------------------------------------------------------------- */
8406033fced289985294e5a3f694646014d80b48ccDarren Armstrong/* The struct comedi_driver structure tells the Comedi core module which     */
8506033fced289985294e5a3f694646014d80b48ccDarren Armstrong/* functions to call to configure/deconfigure (attach/detach) the board, and */
8606033fced289985294e5a3f694646014d80b48ccDarren Armstrong/* also about the kernel module that contains the device code.               */
8718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/*                                                                           */
8818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* In the following section we define the API of this driver.                */
8918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* ------------------------------------------------------------------------- */
9018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
91da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it);
92da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dnp_detach(struct comedi_device *dev);
9318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
94139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pembertonstatic struct comedi_driver driver_dnp = {
9568c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.driver_name = "ssv_dnp",
9668c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.module = THIS_MODULE,
9768c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.attach = dnp_attach,
9868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.detach = dnp_detach,
9968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.board_name = &dnp_boards[0].name,
10018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	/* only necessary for non-PnP devs   */
10106033fced289985294e5a3f694646014d80b48ccDarren Armstrong	.offset = sizeof(struct dnp_board),   /* like ISA-PnP, PCI or PCMCIA */
1028629efa4cbf6f89a54a85af4b8bc31762af01800Bill Pemberton	.num_names = ARRAY_SIZE(dnp_boards),
10318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel};
10418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
1057114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic int __init driver_dnp_init_module(void)
1067114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
1077114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	return comedi_driver_register(&driver_dnp);
1087114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
1097114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
1107114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic void __exit driver_dnp_cleanup_module(void)
1117114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
1127114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	comedi_driver_unregister(&driver_dnp);
1137114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
1147114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
1157114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_init(driver_dnp_init_module);
1167114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_exit(driver_dnp_cleanup_module);
11718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
118da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dnp_dio_insn_bits(struct comedi_device *dev,
1190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s,
1200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_insn *insn, unsigned int *data);
12118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
122da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dnp_dio_insn_config(struct comedi_device *dev,
1230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
1240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data);
12518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
12618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* ------------------------------------------------------------------------- */
12718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* Attach is called by comedi core to configure the driver for a particular  */
12818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* board. If you specified a board_name array in the driver structure,       */
12918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* dev->board_ptr contains that address.                                     */
13018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* ------------------------------------------------------------------------- */
13118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
132da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
13318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel{
13418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
13534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
13618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
13706033fced289985294e5a3f694646014d80b48ccDarren Armstrong	printk(KERN_INFO "comedi%d: dnp: ", dev->minor);
13818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
13906033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* Autoprobing: this should find out which board we have. Currently  */
14006033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* only the 1486 board is supported and autoprobing is not           */
14106033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* implemented :-)                                                   */
1422696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	/* dev->board_ptr = dnp_probe(dev); */
14318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
14406033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* Initialize the name of the board.                                 */
14506033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* We can use the "thisboard" macro now.                             */
14618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	dev->board_name = thisboard->name;
14718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
14806033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* Allocate the private structure area. alloc_private() is a         */
14906033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* convenient macro defined in comedidev.h.                          */
1508532530040c05ab60e7d83c705713ef2629cd3bbBill Pemberton	if (alloc_private(dev, sizeof(struct dnp_private_data)) < 0)
15118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		return -ENOMEM;
15218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
15306033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* Allocate the subdevice structures. alloc_subdevice() is a         */
15406033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* convenient macro defined in comedidev.h.                          */
15518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
15618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	if (alloc_subdevices(dev, 1) < 0)
15718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		return -ENOMEM;
15818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
15918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	s = dev->subdevices + 0;
16006033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* digital i/o subdevice                                             */
16118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	s->type = COMEDI_SUBD_DIO;
16218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
16318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	s->n_chan = 20;
16418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	s->maxdata = 1;
16518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	s->range_table = &range_digital;
16618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	s->insn_bits = dnp_dio_insn_bits;
16718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	s->insn_config = dnp_dio_insn_config;
16818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
16918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	printk("attached\n");
17018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
17118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	/* We use the I/O ports 0x22,0x23 and 0xa3-0xa9, which are always
17218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	 * allocated for the primary 8259, so we don't need to allocate them
17318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	 * ourselves. */
17418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
17506033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* configure all ports as input (default)                            */
17618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	outb(PAMR, CSCIR);
17718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	outb(0x00, CSCDR);
17818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	outb(PBMR, CSCIR);
17918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	outb(0x00, CSCDR);
18018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	outb(PCMR, CSCIR);
18118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	outb((inb(CSCDR) & 0xAA), CSCDR);
18218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
18318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	return 1;
18418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
18518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel}
18618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
18718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* ------------------------------------------------------------------------- */
18818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* detach is called to deconfigure a device. It should deallocate the        */
18918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* resources. This function is also called when _attach() fails, so it       */
19018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* should be careful not to release resources that were not necessarily      */
19118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* allocated by _attach(). dev->private and dev->subdevices are              */
19218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* deallocated automatically by the core.                                    */
19318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* ------------------------------------------------------------------------- */
19418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
195da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dnp_detach(struct comedi_device *dev)
19618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel{
19718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
19806033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* configure all ports as input (default)                            */
19918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	outb(PAMR, CSCIR);
20018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	outb(0x00, CSCDR);
20118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	outb(PBMR, CSCIR);
20218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	outb(0x00, CSCDR);
20318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	outb(PCMR, CSCIR);
20418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	outb((inb(CSCDR) & 0xAA), CSCDR);
20518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
20606033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* announce that we are finished                                     */
20706033fced289985294e5a3f694646014d80b48ccDarren Armstrong	printk(KERN_INFO "comedi%d: dnp: remove\n", dev->minor);
20818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
20918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	return 0;
21018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
21118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel}
21218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
21318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* ------------------------------------------------------------------------- */
21418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* The insn_bits interface allows packed reading/writing of DIO channels.    */
21518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* The comedi core can convert between insn_bits and insn_read/write, so you */
21618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* are able to use these instructions as well.                               */
21718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* ------------------------------------------------------------------------- */
21818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
219da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dnp_dio_insn_bits(struct comedi_device *dev,
2200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s,
2210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_insn *insn, unsigned int *data)
22218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel{
22318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
22418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	if (insn->n != 2)
22518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		return -EINVAL;	/* insn uses data[0] and data[1]     */
22618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
22706033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* The insn data is a mask in data[0] and the new data in data[1],   */
22806033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* each channel cooresponding to a bit.                              */
22918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
23006033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* Ports A and B are straight forward: each bit corresponds to an    */
23106033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* output pin with the same order. Port C is different: bits 0...3   */
23206033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* correspond to bits 4...7 of the output register (PCDR).           */
23318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
23418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	if (data[0]) {
23518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
23618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		outb(PADR, CSCIR);
23718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		outb((inb(CSCDR)
2380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		      & ~(u8) (data[0] & 0x0000FF))
2390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		     | (u8) (data[1] & 0x0000FF), CSCDR);
24018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
24118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		outb(PBDR, CSCIR);
24218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		outb((inb(CSCDR)
2430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		      & ~(u8) ((data[0] & 0x00FF00) >> 8))
2440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		     | (u8) ((data[1] & 0x00FF00) >> 8), CSCDR);
24518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
24618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		outb(PCDR, CSCIR);
24718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		outb((inb(CSCDR)
2480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		      & ~(u8) ((data[0] & 0x0F0000) >> 12))
2490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		     | (u8) ((data[1] & 0x0F0000) >> 12), CSCDR);
25018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	}
25118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
25206033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* on return, data[1] contains the value of the digital input lines. */
25318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	outb(PADR, CSCIR);
25418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	data[0] = inb(CSCDR);
25518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	outb(PBDR, CSCIR);
25618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	data[0] += inb(CSCDR) << 8;
25718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	outb(PCDR, CSCIR);
25818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	data[0] += ((inb(CSCDR) & 0xF0) << 12);
25918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
26018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	return 2;
26118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
26218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel}
26318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
26418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* ------------------------------------------------------------------------- */
26518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* Configure the direction of the bidirectional digital i/o pins. chanspec   */
26618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* contains the channel to be changed and data[0] contains either            */
26718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* COMEDI_INPUT or COMEDI_OUTPUT.                                            */
26818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel/* ------------------------------------------------------------------------- */
26918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
270da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dnp_dio_insn_config(struct comedi_device *dev,
2710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
2720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data)
27318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel{
27418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
27518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	u8 register_buffer;
27618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
27706033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* reduces chanspec to lower 16 bits */
27806033fced289985294e5a3f694646014d80b48ccDarren Armstrong	int chan = CR_CHAN(insn->chanspec);
27918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
28018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	switch (data[0]) {
28118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	case INSN_CONFIG_DIO_OUTPUT:
28218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	case INSN_CONFIG_DIO_INPUT:
28318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		break;
28418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	case INSN_CONFIG_DIO_QUERY:
28518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		data[1] =
2860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (inb(CSCDR) & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
28718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		return insn->n;
28818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		break;
28918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	default:
29018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		return -EINVAL;
29118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		break;
29218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	}
29306033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* Test: which port does the channel belong to?                       */
29418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
29506033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* We have to pay attention with port C: this is the meaning of PCMR: */
29606033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* Bit in PCMR:              7 6 5 4 3 2 1 0                          */
29706033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* Corresponding port C pin: d 3 d 2 d 1 d 0   d= don't touch         */
29818222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
29918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	if ((chan >= 0) && (chan <= 7)) {
30018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		/* this is port A */
30118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		outb(PAMR, CSCIR);
30218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	} else if ((chan >= 8) && (chan <= 15)) {
30318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		/* this is port B */
30418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		chan -= 8;
30518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		outb(PBMR, CSCIR);
30618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	} else if ((chan >= 16) && (chan <= 19)) {
30706033fced289985294e5a3f694646014d80b48ccDarren Armstrong		/* this is port C; multiplication with 2 brings bits into     */
30806033fced289985294e5a3f694646014d80b48ccDarren Armstrong		/* correct position for PCMR!                                 */
30918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		chan -= 16;
31018222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		chan *= 2;
31118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		outb(PCMR, CSCIR);
31218222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	} else {
31318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		return -EINVAL;
31418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	}
31518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
31606033fced289985294e5a3f694646014d80b48ccDarren Armstrong	/* read 'old' direction of the port and set bits (out=1, in=0)        */
31718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	register_buffer = inb(CSCDR);
318dee86e8c9279110d787da64cbca5d4bda63d93c6Greg Kroah-Hartman	if (data[0] == COMEDI_OUTPUT)
31918222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		register_buffer |= (1 << chan);
320dee86e8c9279110d787da64cbca5d4bda63d93c6Greg Kroah-Hartman	else
32118222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel		register_buffer &= ~(1 << chan);
322dee86e8c9279110d787da64cbca5d4bda63d93c6Greg Kroah-Hartman
32318222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	outb(register_buffer, CSCDR);
32418222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
32518222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel	return 1;
32618222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel
32718222f98223a00537bcf29ba74c8d5fdb3ae1fb8Robert Schwebel}
32890f703d30dd3e0c16ff80f35e34e511385a05ad5Arun Thomas
32990f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_AUTHOR("Comedi http://www.comedi.org");
33090f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_DESCRIPTION("Comedi low-level driver");
33190f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_LICENSE("GPL");
332