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 | ||
29 | #include "../comedidev.h" | |
30 | ||
31 | /* Some global definitions: the registers of the DNP ----------------------- */ | |
32 | /* */ | |
33 | /* For port A and B the mode register has bits corresponding to the output */ | |
34 | /* pins, where Bit-N = 0 -> input, Bit-N = 1 -> output. Note that bits */ | |
35 | /* 4 to 7 correspond to pin 0..3 for port C data register. Ensure that bits */ | |
36 | /* 0..3 remain unchanged! For details about Port C Mode Register see */ | |
37 | /* the remarks in dnp_insn_config() below. */ | |
38 | ||
06033fce DA |
39 | #define CSCIR 0x22 /* Chip Setup and Control Index Register */ |
40 | #define CSCDR 0x23 /* Chip Setup and Control Data Register */ | |
41 | #define PAMR 0xa5 /* Port A Mode Register */ | |
42 | #define PADR 0xa9 /* Port A Data Register */ | |
43 | #define PBMR 0xa4 /* Port B Mode Register */ | |
44 | #define PBDR 0xa8 /* Port B Data Register */ | |
45 | #define PCMR 0xa3 /* Port C Mode Register */ | |
46 | #define PCDR 0xa7 /* Port C Data Register */ | |
18222f98 | 47 | |
18222f98 RS |
48 | /* ------------------------------------------------------------------------- */ |
49 | /* The insn_bits interface allows packed reading/writing of DIO channels. */ | |
50 | /* The comedi core can convert between insn_bits and insn_read/write, so you */ | |
51 | /* are able to use these instructions as well. */ | |
52 | /* ------------------------------------------------------------------------- */ | |
53 | ||
da91b269 | 54 | static int dnp_dio_insn_bits(struct comedi_device *dev, |
0a85b6f0 MT |
55 | struct comedi_subdevice *s, |
56 | struct comedi_insn *insn, unsigned int *data) | |
18222f98 | 57 | { |
06033fce DA |
58 | /* The insn data is a mask in data[0] and the new data in data[1], */ |
59 | /* each channel cooresponding to a bit. */ | |
18222f98 | 60 | |
06033fce DA |
61 | /* Ports A and B are straight forward: each bit corresponds to an */ |
62 | /* output pin with the same order. Port C is different: bits 0...3 */ | |
63 | /* correspond to bits 4...7 of the output register (PCDR). */ | |
18222f98 RS |
64 | |
65 | if (data[0]) { | |
66 | ||
67 | outb(PADR, CSCIR); | |
68 | outb((inb(CSCDR) | |
0a85b6f0 MT |
69 | & ~(u8) (data[0] & 0x0000FF)) |
70 | | (u8) (data[1] & 0x0000FF), CSCDR); | |
18222f98 RS |
71 | |
72 | outb(PBDR, CSCIR); | |
73 | outb((inb(CSCDR) | |
0a85b6f0 MT |
74 | & ~(u8) ((data[0] & 0x00FF00) >> 8)) |
75 | | (u8) ((data[1] & 0x00FF00) >> 8), CSCDR); | |
18222f98 RS |
76 | |
77 | outb(PCDR, CSCIR); | |
78 | outb((inb(CSCDR) | |
0a85b6f0 MT |
79 | & ~(u8) ((data[0] & 0x0F0000) >> 12)) |
80 | | (u8) ((data[1] & 0x0F0000) >> 12), CSCDR); | |
18222f98 RS |
81 | } |
82 | ||
06033fce | 83 | /* on return, data[1] contains the value of the digital input lines. */ |
18222f98 RS |
84 | outb(PADR, CSCIR); |
85 | data[0] = inb(CSCDR); | |
86 | outb(PBDR, CSCIR); | |
87 | data[0] += inb(CSCDR) << 8; | |
88 | outb(PCDR, CSCIR); | |
89 | data[0] += ((inb(CSCDR) & 0xF0) << 12); | |
90 | ||
a2714e3e | 91 | return insn->n; |
18222f98 RS |
92 | |
93 | } | |
94 | ||
95 | /* ------------------------------------------------------------------------- */ | |
96 | /* Configure the direction of the bidirectional digital i/o pins. chanspec */ | |
97 | /* contains the channel to be changed and data[0] contains either */ | |
98 | /* COMEDI_INPUT or COMEDI_OUTPUT. */ | |
99 | /* ------------------------------------------------------------------------- */ | |
100 | ||
da91b269 | 101 | static int dnp_dio_insn_config(struct comedi_device *dev, |
0a85b6f0 MT |
102 | struct comedi_subdevice *s, |
103 | struct comedi_insn *insn, unsigned int *data) | |
18222f98 RS |
104 | { |
105 | ||
106 | u8 register_buffer; | |
107 | ||
06033fce DA |
108 | /* reduces chanspec to lower 16 bits */ |
109 | int chan = CR_CHAN(insn->chanspec); | |
18222f98 RS |
110 | |
111 | switch (data[0]) { | |
112 | case INSN_CONFIG_DIO_OUTPUT: | |
113 | case INSN_CONFIG_DIO_INPUT: | |
114 | break; | |
115 | case INSN_CONFIG_DIO_QUERY: | |
116 | data[1] = | |
0a85b6f0 | 117 | (inb(CSCDR) & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; |
18222f98 RS |
118 | return insn->n; |
119 | break; | |
120 | default: | |
121 | return -EINVAL; | |
122 | break; | |
123 | } | |
06033fce | 124 | /* Test: which port does the channel belong to? */ |
18222f98 | 125 | |
06033fce DA |
126 | /* We have to pay attention with port C: this is the meaning of PCMR: */ |
127 | /* Bit in PCMR: 7 6 5 4 3 2 1 0 */ | |
128 | /* Corresponding port C pin: d 3 d 2 d 1 d 0 d= don't touch */ | |
18222f98 RS |
129 | |
130 | if ((chan >= 0) && (chan <= 7)) { | |
131 | /* this is port A */ | |
132 | outb(PAMR, CSCIR); | |
133 | } else if ((chan >= 8) && (chan <= 15)) { | |
134 | /* this is port B */ | |
135 | chan -= 8; | |
136 | outb(PBMR, CSCIR); | |
137 | } else if ((chan >= 16) && (chan <= 19)) { | |
06033fce DA |
138 | /* this is port C; multiplication with 2 brings bits into */ |
139 | /* correct position for PCMR! */ | |
18222f98 RS |
140 | chan -= 16; |
141 | chan *= 2; | |
142 | outb(PCMR, CSCIR); | |
143 | } else { | |
144 | return -EINVAL; | |
145 | } | |
146 | ||
06033fce | 147 | /* read 'old' direction of the port and set bits (out=1, in=0) */ |
18222f98 | 148 | register_buffer = inb(CSCDR); |
dee86e8c | 149 | if (data[0] == COMEDI_OUTPUT) |
18222f98 | 150 | register_buffer |= (1 << chan); |
dee86e8c | 151 | else |
18222f98 | 152 | register_buffer &= ~(1 << chan); |
dee86e8c | 153 | |
18222f98 RS |
154 | outb(register_buffer, CSCDR); |
155 | ||
156 | return 1; | |
157 | ||
158 | } | |
90f703d3 | 159 | |
f1decb9b HS |
160 | static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) |
161 | { | |
162 | struct comedi_subdevice *s; | |
8b6c5694 | 163 | int ret; |
f1decb9b | 164 | |
8b6c5694 HS |
165 | ret = comedi_alloc_subdevices(dev, 1); |
166 | if (ret) | |
167 | return ret; | |
f1decb9b | 168 | |
015ebbe8 | 169 | s = &dev->subdevices[0]; |
f1decb9b HS |
170 | /* digital i/o subdevice */ |
171 | s->type = COMEDI_SUBD_DIO; | |
172 | s->subdev_flags = SDF_READABLE | SDF_WRITABLE; | |
173 | s->n_chan = 20; | |
174 | s->maxdata = 1; | |
175 | s->range_table = &range_digital; | |
176 | s->insn_bits = dnp_dio_insn_bits; | |
177 | s->insn_config = dnp_dio_insn_config; | |
178 | ||
f1decb9b HS |
179 | /* We use the I/O ports 0x22,0x23 and 0xa3-0xa9, which are always |
180 | * allocated for the primary 8259, so we don't need to allocate them | |
181 | * ourselves. */ | |
182 | ||
183 | /* configure all ports as input (default) */ | |
184 | outb(PAMR, CSCIR); | |
185 | outb(0x00, CSCDR); | |
186 | outb(PBMR, CSCIR); | |
187 | outb(0x00, CSCDR); | |
188 | outb(PCMR, CSCIR); | |
189 | outb((inb(CSCDR) & 0xAA), CSCDR); | |
190 | ||
53fa8c46 | 191 | dev_info(dev->class_dev, "%s: attached\n", dev->board_name); |
f1decb9b HS |
192 | return 1; |
193 | } | |
194 | ||
484ecc95 | 195 | static void dnp_detach(struct comedi_device *dev) |
f1decb9b | 196 | { |
f1decb9b HS |
197 | outb(PAMR, CSCIR); |
198 | outb(0x00, CSCDR); | |
199 | outb(PBMR, CSCIR); | |
200 | outb(0x00, CSCDR); | |
201 | outb(PCMR, CSCIR); | |
202 | outb((inb(CSCDR) & 0xAA), CSCDR); | |
f1decb9b HS |
203 | } |
204 | ||
f1decb9b | 205 | static struct comedi_driver dnp_driver = { |
b25e0923 | 206 | .driver_name = "dnp-1486", |
f1decb9b HS |
207 | .module = THIS_MODULE, |
208 | .attach = dnp_attach, | |
209 | .detach = dnp_detach, | |
f1decb9b HS |
210 | }; |
211 | module_comedi_driver(dnp_driver); | |
212 | ||
90f703d3 AT |
213 | MODULE_AUTHOR("Comedi http://www.comedi.org"); |
214 | MODULE_DESCRIPTION("Comedi low-level driver"); | |
215 | MODULE_LICENSE("GPL"); |