Commit | Line | Data |
---|---|---|
18222f98 RS |
1 | /* |
2 | comedi/drivers/ssv_dnp.c | |
3 | generic comedi driver for SSV Embedded Systems' DIL/Net-PCs | |
4 | Copyright (C) 2001 Robert Schwebel <robert@schwebel.de> | |
5 | ||
6 | COMEDI - Linux Control and Measurement Device Interface | |
7 | Copyright (C) 2000 David A. Schleef <ds@schleef.org> | |
8 | ||
9 | This program is free software; you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation; either version 2 of the License, or | |
12 | (at your option) any later version. | |
13 | ||
14 | This program is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18222f98 RS |
18 | */ |
19 | /* | |
20 | Driver: ssv_dnp | |
21 | Description: SSV Embedded Systems DIL/Net-PC | |
22 | Author: Robert Schwebel <robert@schwebel.de> | |
23 | Devices: [SSV Embedded Systems] DIL/Net-PC 1486 (dnp-1486) | |
24 | Status: unknown | |
25 | */ | |
26 | ||
27 | /* include files ----------------------------------------------------------- */ | |
28 | ||
ce157f80 | 29 | #include <linux/module.h> |
18222f98 RS |
30 | #include "../comedidev.h" |
31 | ||
32 | /* Some global definitions: the registers of the DNP ----------------------- */ | |
33 | /* */ | |
34 | /* For port A and B the mode register has bits corresponding to the output */ | |
35 | /* pins, where Bit-N = 0 -> input, Bit-N = 1 -> output. Note that bits */ | |
36 | /* 4 to 7 correspond to pin 0..3 for port C data register. Ensure that bits */ | |
37 | /* 0..3 remain unchanged! For details about Port C Mode Register see */ | |
38 | /* the remarks in dnp_insn_config() below. */ | |
39 | ||
06033fce DA |
40 | #define CSCIR 0x22 /* Chip Setup and Control Index Register */ |
41 | #define CSCDR 0x23 /* Chip Setup and Control Data Register */ | |
42 | #define PAMR 0xa5 /* Port A Mode Register */ | |
43 | #define PADR 0xa9 /* Port A Data Register */ | |
44 | #define PBMR 0xa4 /* Port B Mode Register */ | |
45 | #define PBDR 0xa8 /* Port B Data Register */ | |
46 | #define PCMR 0xa3 /* Port C Mode Register */ | |
47 | #define PCDR 0xa7 /* Port C Data Register */ | |
18222f98 | 48 | |
da91b269 | 49 | static int dnp_dio_insn_bits(struct comedi_device *dev, |
0a85b6f0 | 50 | struct comedi_subdevice *s, |
f6b316bc HS |
51 | struct comedi_insn *insn, |
52 | unsigned int *data) | |
18222f98 | 53 | { |
f6b316bc HS |
54 | unsigned int mask; |
55 | unsigned int val; | |
18222f98 | 56 | |
f6b316bc HS |
57 | /* |
58 | * Ports A and B are straight forward: each bit corresponds to an | |
59 | * output pin with the same order. Port C is different: bits 0...3 | |
60 | * correspond to bits 4...7 of the output register (PCDR). | |
61 | */ | |
18222f98 | 62 | |
f6b316bc HS |
63 | mask = comedi_dio_update_state(s, data); |
64 | if (mask) { | |
18222f98 | 65 | outb(PADR, CSCIR); |
f6b316bc | 66 | outb(s->state & 0xff, CSCDR); |
18222f98 RS |
67 | |
68 | outb(PBDR, CSCIR); | |
f6b316bc | 69 | outb((s->state >> 8) & 0xff, CSCDR); |
18222f98 RS |
70 | |
71 | outb(PCDR, CSCIR); | |
f6b316bc HS |
72 | val = inb(CSCDR) & 0x0f; |
73 | outb(((s->state >> 12) & 0xf0) | val, CSCDR); | |
18222f98 RS |
74 | } |
75 | ||
18222f98 | 76 | outb(PADR, CSCIR); |
f6b316bc | 77 | val = inb(CSCDR); |
18222f98 | 78 | outb(PBDR, CSCIR); |
f6b316bc | 79 | val |= (inb(CSCDR) << 8); |
18222f98 | 80 | outb(PCDR, CSCIR); |
f6b316bc | 81 | val |= ((inb(CSCDR) & 0xf0) << 12); |
18222f98 | 82 | |
f6b316bc | 83 | data[1] = val; |
18222f98 | 84 | |
f6b316bc | 85 | return insn->n; |
18222f98 RS |
86 | } |
87 | ||
da91b269 | 88 | static int dnp_dio_insn_config(struct comedi_device *dev, |
0a85b6f0 | 89 | struct comedi_subdevice *s, |
ddf62f2c HS |
90 | struct comedi_insn *insn, |
91 | unsigned int *data) | |
18222f98 | 92 | { |
ddf62f2c HS |
93 | unsigned int chan = CR_CHAN(insn->chanspec); |
94 | unsigned int mask; | |
95 | unsigned int val; | |
96 | int ret; | |
18222f98 | 97 | |
ddf62f2c HS |
98 | ret = comedi_dio_insn_config(dev, s, insn, data, 0); |
99 | if (ret) | |
100 | return ret; | |
18222f98 | 101 | |
ddf62f2c HS |
102 | if (chan < 8) { /* Port A */ |
103 | mask = 1 << chan; | |
18222f98 | 104 | outb(PAMR, CSCIR); |
ddf62f2c HS |
105 | } else if (chan < 16) { /* Port B */ |
106 | mask = 1 << (chan - 8); | |
18222f98 | 107 | outb(PBMR, CSCIR); |
ddf62f2c HS |
108 | } else { /* Port C */ |
109 | /* | |
110 | * We have to pay attention with port C. | |
111 | * This is the meaning of PCMR: | |
112 | * Bit in PCMR: 7 6 5 4 3 2 1 0 | |
113 | * Corresponding port C pin: d 3 d 2 d 1 d 0 d= don't touch | |
114 | * | |
115 | * Multiplication by 2 brings bits into correct position | |
116 | * for PCMR! | |
117 | */ | |
118 | mask = 1 << ((chan - 16) * 2); | |
18222f98 | 119 | outb(PCMR, CSCIR); |
18222f98 RS |
120 | } |
121 | ||
ddf62f2c | 122 | val = inb(CSCDR); |
dee86e8c | 123 | if (data[0] == COMEDI_OUTPUT) |
ddf62f2c | 124 | val |= mask; |
dee86e8c | 125 | else |
ddf62f2c HS |
126 | val &= ~mask; |
127 | outb(val, CSCDR); | |
dee86e8c | 128 | |
ddf62f2c | 129 | return insn->n; |
18222f98 RS |
130 | |
131 | } | |
90f703d3 | 132 | |
f1decb9b HS |
133 | static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) |
134 | { | |
135 | struct comedi_subdevice *s; | |
8b6c5694 | 136 | int ret; |
f1decb9b | 137 | |
8b6c5694 HS |
138 | ret = comedi_alloc_subdevices(dev, 1); |
139 | if (ret) | |
140 | return ret; | |
f1decb9b | 141 | |
015ebbe8 | 142 | s = &dev->subdevices[0]; |
f1decb9b HS |
143 | /* digital i/o subdevice */ |
144 | s->type = COMEDI_SUBD_DIO; | |
145 | s->subdev_flags = SDF_READABLE | SDF_WRITABLE; | |
146 | s->n_chan = 20; | |
147 | s->maxdata = 1; | |
148 | s->range_table = &range_digital; | |
149 | s->insn_bits = dnp_dio_insn_bits; | |
150 | s->insn_config = dnp_dio_insn_config; | |
151 | ||
f1decb9b HS |
152 | /* We use the I/O ports 0x22,0x23 and 0xa3-0xa9, which are always |
153 | * allocated for the primary 8259, so we don't need to allocate them | |
154 | * ourselves. */ | |
155 | ||
156 | /* configure all ports as input (default) */ | |
157 | outb(PAMR, CSCIR); | |
158 | outb(0x00, CSCDR); | |
159 | outb(PBMR, CSCIR); | |
160 | outb(0x00, CSCDR); | |
161 | outb(PCMR, CSCIR); | |
162 | outb((inb(CSCDR) & 0xAA), CSCDR); | |
163 | ||
c93999c2 | 164 | return 0; |
f1decb9b HS |
165 | } |
166 | ||
484ecc95 | 167 | static void dnp_detach(struct comedi_device *dev) |
f1decb9b | 168 | { |
f1decb9b HS |
169 | outb(PAMR, CSCIR); |
170 | outb(0x00, CSCDR); | |
171 | outb(PBMR, CSCIR); | |
172 | outb(0x00, CSCDR); | |
173 | outb(PCMR, CSCIR); | |
174 | outb((inb(CSCDR) & 0xAA), CSCDR); | |
f1decb9b HS |
175 | } |
176 | ||
f1decb9b | 177 | static struct comedi_driver dnp_driver = { |
b25e0923 | 178 | .driver_name = "dnp-1486", |
f1decb9b HS |
179 | .module = THIS_MODULE, |
180 | .attach = dnp_attach, | |
181 | .detach = dnp_detach, | |
f1decb9b HS |
182 | }; |
183 | module_comedi_driver(dnp_driver); | |
184 | ||
90f703d3 AT |
185 | MODULE_AUTHOR("Comedi http://www.comedi.org"); |
186 | MODULE_DESCRIPTION("Comedi low-level driver"); | |
187 | MODULE_LICENSE("GPL"); |