-
Notifications
You must be signed in to change notification settings - Fork 2
/
bus.c
259 lines (229 loc) · 5.14 KB
/
bus.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
#include "wago.h"
#include "bus.h"
#include "kbusapi.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
extern char debug;
// cat /proc/driver/kbus/config.csv
//line ?? ?? rboff woffset wwidth
// name bits roffset rwidth wboff
//1 750-4xx 0 8 n 0 0 0 0 0 8
//1 750-5xx 0 16 n 0 0 16 0 0 0
//2 750-5xx 0 16 n 2 0 16 0 0 0
struct _bus_priv;
struct _bus_priv {
struct _bus bus;
struct _bus_priv *next;
unsigned char byte_offset, bit_offset;
};
static struct _bus_priv *bus_list = NULL;
static const char *bus_file = NULL;
/* Initialize/free data */
int bus_init_data(const char *fn)
{
FILE *f;
int res = 0;
#ifdef DEMO
if(fn == NULL)
return 0;
bus_file = strdup(fn);
#else
if(fn == NULL) {
fn = "/proc/driver/kbus/config.csv";
bus_file = "/proc/driver/kbus/config";
}
res = KbusOpen();
if(res < 0)
return res;
#endif
f = fopen(fn,"r");
if (f == NULL)
return -errno;
while(1) {
struct _bus_priv *dev;
char devtyp[BUS_TYPNAME_LEN],x3[3];
int i,x1,bits;
int roff,rboff,rsiz;
int woff,wboff,wsiz;
int len = fscanf(f,"%d %10s %d %d %2s %d %d %d %d %d %d\n",
&i,devtyp,&x1,&bits,x3, &woff,&wboff,&wsiz, &roff,&rboff,&rsiz);
if (len == 0)
break;
if (len != 11) {
if (len > 0)
res = -EINVAL;
return res;
}
dev = malloc(sizeof(*dev));
if (dev == NULL) {
res = -errno;
break;
}
memset(dev,0,sizeof(*dev));
dev->bus.id = i;
strcpy(dev->bus.typname,devtyp);
if(!strcmp(devtyp,"750-5xx")) { // digital output
dev->bus.typ = BUS_BITS_OUT;
dev->byte_offset = woff;
dev->bit_offset = wboff;
dev->bus.bits = wsiz;
} else if(!strcmp(devtyp,"750-4xx")) { // digital output
dev->bus.typ = BUS_BITS_IN;
dev->byte_offset = roff;
dev->bit_offset = rboff;
dev->bus.bits = rsiz;
} else {
dev->bus.typ = BUS_UNKNOWN;
}
dev->next = bus_list;
bus_list = dev;
}
fclose(f);
return res;
}
void bus_free_data()
{
#ifndef DEMO
KbusClose();
#endif
}
/* return a file with data describing the bus */
FILE *bus_description(void)
{
if (bus_file == NULL)
bus_file = "/dev/null";
return fopen(bus_file,"r");
}
/* Enumerate the bus. Return something != 0 to break the enumerator loop. */
// int (*bus_enum_fn)(struct _bus *bus, void *priv);
int bus_enum(bus_enum_fn enum_fn, void *priv)
{
struct _bus_priv *bus;
int res = 0;
for(bus = bus_list; bus; bus = bus->next) {
res = (*enum_fn)(&bus->bus, priv);
if (res)
break;
}
return res;
}
const char *bus_typname(enum bus_type typ)
{
switch(typ) {
case BUS_UNKNOWN:
return "unknown device";
case BUS_BITS_IN:
return "digital input";
case BUS_BITS_OUT:
return "digital output";
default:
return "???";
}
}
/* sync bus state */
void bus_sync()
{
#ifndef DEMO
KbusUpdate();
#endif
}
/*
Check if this bit is on the bus.
Input: Slot number and -based bit position.
Output: Byte and bit offset for hardware access.
Returns: -1 if invalid oarameters, else 0.
*/
int _bus_find_bit(unsigned short *_port,unsigned short *_offset, enum bus_type typ)
{
struct _bus_priv *bus;
unsigned short port = *_port;
unsigned short offset = *_offset;
for(bus = bus_list; bus; bus = bus->next) {
if (bus->bus.id != port)
continue;
if (bus->bus.typ != typ) {
errno = EINVAL;
if(debug)
fprintf(stderr, "Check %d %d for %s FAILED: wrong device\n",port,offset,bus_typname(typ));
return -1;
}
if (offset == 0 || offset > bus->bus.bits) {
errno = EINVAL;
if(debug)
fprintf(stderr, "Check %d %d for %s FAILED: max %d bits\n",port,offset,bus_typname(typ), bus->bus.bits);
return -1;
}
offset += bus->bit_offset-1;
*_port = bus->byte_offset + (offset>>3);
*_offset = offset & 7;
return 0;
}
if(debug)
fprintf(stderr, "Check %d %d for %s FAILED: ID not found\n",port,offset,bus_typname(typ));
errno = ENODEV;
return -1;
}
int bus_is_read_bit(unsigned short *port,unsigned short *offset)
{
return _bus_find_bit(port,offset,BUS_BITS_IN);
}
int bus_is_write_bit(unsigned short *port,unsigned short *offset)
{
return _bus_find_bit(port,offset,BUS_BITS_OUT);
}
/* read a bit, or return a bit's write status */
char _bus_read_bit(unsigned short port,unsigned short offset)
{
char res = 0;
#ifdef DEMO
if (demo_rand)
res = (rand() < RAND_MAX/10);
else
res = 0;
if (res)
res = 1-demo_state_r;
else
res = demo_state_r;
#else
res = (pstPabIN->uc.Pab[port] & (1<<offset)) ? 1 : 0;
#endif
if(debug)
fprintf(stderr, " bit %d:%d = %d\n", port,offset, res);
return res;
}
char _bus_read_wbit(unsigned short port,unsigned short offset)
{
char res = 0;
#ifdef DEMO
if (demo_rand)
res = (rand() < RAND_MAX/10);
else
res = 0;
if (res)
res = 1-demo_state_w;
else
res = demo_state_w;
#else
res = (pstPabOUT->uc.Pab[port] & (1<<offset)) ? 1 : 0;
#endif
if(debug)
fprintf(stderr, " wbit %d:%d = %d\n", port,offset, res);
return res;
}
/* write a bit */
void _bus_write_bit(unsigned short port,unsigned short offset, char value)
{
if(debug)
fprintf(stderr,"Set bit %d:%d = %d\n", port,offset, value);
#ifdef DEMO
demo_state_w = value;
#else
if (value) {
pstPabOUT->uc.Pab[port] |= 1<<offset;
} else {
pstPabOUT->uc.Pab[port] &= ~(1<<offset);
}
#endif
}