aea5f3266d04596edeacdde157f6303d04a446f6
[comedilib.git] / scxi / scxi.c
1 #include "comedilib_scxi.h"
2 #include <string.h>
3 #include <stdlib.h>
4 #include <byteswap.h>
5
6 static int scxi_identify(scxi_mod_t *mod);
7
8 static int scxi_serial_config(comedi_t *it, unsigned int clock_interval)
9 {
10         comedi_insn insn;
11         lsampl_t data[2];
12
13         memset(&insn,0,sizeof(insn));
14         insn.insn = INSN_CONFIG;
15         insn.n = 2;
16         insn.data = &data[0];
17         insn.subdev = comedi_find_subdevice_by_type(it, COMEDI_SUBD_SERIAL, 0);
18         data[0]=INSN_CONFIG_SERIAL_CLOCK;
19         data[1]=clock_interval;
20
21         return comedi_do_insn(it,&insn);
22 }
23
24 static int scxi_serial_readwrite(comedi_t *it, unsigned char out_bits, unsigned char *in_bits)
25 {
26         int ret;
27         comedi_insn insn;
28         lsampl_t data[2];
29
30         memset(&insn,0,sizeof(insn));
31
32         insn.insn = INSN_CONFIG;
33         insn.n = 2;
34         insn.data = data;
35         insn.subdev = comedi_find_subdevice_by_type(it, COMEDI_SUBD_SERIAL, 0);
36
37         data[0]=INSN_CONFIG_BIDIRECTIONAL_DATA;
38         data[1]=out_bits;
39
40         ret = comedi_do_insn(it,&insn);
41
42         if(ret<0) return ret;
43
44         if(in_bits)
45                 *in_bits = data[1];
46
47         return 0;
48 }
49
50 static int local_serial_readwrite(comedi_t *it, unsigned int subdev, unsigned int num_bits,
51         unsigned int out_bits, unsigned int *in_bits)
52 {
53         unsigned char byte_out, byte_in;
54         while(num_bits > 0) {
55                 if(in_bits != NULL) (*in_bits) <<= 8;
56                 byte_out = (out_bits >> (num_bits - 8)) & 0xFF;
57                 scxi_serial_readwrite(it,byte_out, &byte_in);
58                 if(in_bits != NULL) *in_bits |= byte_in;
59
60                 num_bits -= 8;
61         }
62         return 0;
63 }
64
65 static int scxi_slot_select(comedi_t *dev, unsigned int dio_subdev, 
66         unsigned int serial_subdev, unsigned short chassis_address, unsigned short module_slot)
67 {
68         const unsigned int ssreg = ((chassis_address & 0x1f) << 4) | (module_slot & 0x0f);
69
70         comedi_dio_write(dev, dio_subdev, SCXI_LINE_SS, 0);
71         scxi_serial_config(dev, SLOT0_INTERVAL);
72         local_serial_readwrite(dev, serial_subdev, 16, ssreg, NULL);
73         comedi_dio_write(dev, dio_subdev, SCXI_LINE_SS, 1);
74         
75         return 0;
76 }
77
78 void comedi_scxi_close(scxi_mod_t *mod)
79 {
80         free(mod);
81 }
82
83 scxi_mod_t *comedi_scxi_open(comedi_t *dev, unsigned short chassis_address, unsigned short mod_slot)
84 {
85         scxi_mod_t *mod = NULL;
86         
87         mod = (scxi_mod_t *) malloc(sizeof(*mod));
88         if(mod == NULL) goto Error;
89         
90         memset(mod, 0, sizeof(*mod));
91         mod->chassis = chassis_address;
92         mod->slot = mod_slot;
93         
94         mod->dev = dev;
95         if(mod->dev == NULL) goto Error;
96         
97         mod->dio_subdev = comedi_find_subdevice_by_type(mod->dev, COMEDI_SUBD_DIO, 0);
98         mod->ser_subdev = comedi_find_subdevice_by_type(mod->dev, COMEDI_SUBD_SERIAL, 0);
99         
100         comedi_dio_config(mod->dev, mod->dio_subdev, SCXI_LINE_MISO, COMEDI_INPUT);
101         comedi_dio_config(mod->dev, mod->dio_subdev, SCXI_LINE_DA, COMEDI_OUTPUT);
102         comedi_dio_config(mod->dev, mod->dio_subdev, SCXI_LINE_SS, COMEDI_OUTPUT);
103         comedi_dio_config(mod->dev, mod->dio_subdev, SCXI_LINE_MOSI, COMEDI_OUTPUT);
104                 
105         comedi_dio_write(mod->dev, mod->dio_subdev, SCXI_LINE_DA, 1);
106         comedi_dio_write(mod->dev, mod->dio_subdev, SCXI_LINE_SS, 1);
107
108         scxi_identify(mod);
109         
110         return mod;
111         
112 Error:
113         comedi_scxi_close(mod);
114         return NULL;
115 }
116
117 static int scxi_module_select(scxi_mod_t *mod, unsigned short address)
118 {
119         scxi_slot_select(mod->dev, mod->dio_subdev, mod->ser_subdev, mod->chassis, mod->slot);
120
121         if(scxi_serial_config(mod->dev, scxi_boards[mod->board].clock_interval) < 0)
122                 return -1;
123
124         if(scxi_boards[mod->board].modclass == 2)
125                 if(local_serial_readwrite(mod->dev, mod->ser_subdev, 16, address, NULL) < 0) return -1;
126
127         if(comedi_dio_write(mod->dev, mod->dio_subdev, SCXI_LINE_DA, 0) < 0) return -1;
128
129         return 0;
130 }
131
132 static int scxi_module_deselect(scxi_mod_t *mod)
133 {
134         if(comedi_dio_write(mod->dev, mod->dio_subdev, SCXI_LINE_DA, 1) < 0) return -1;
135
136         if(scxi_boards[mod->board].modclass == 2) {
137         if(local_serial_readwrite(mod->dev, mod->ser_subdev, 16, REG_PARK, NULL) < 0) return -1;
138         }
139         
140         scxi_slot_select(mod->dev, mod->dio_subdev, mod->ser_subdev, mod->chassis, 0);
141         
142         return 0;
143 }
144
145 static int scxi_identify(scxi_mod_t *mod)
146 {
147         unsigned int id, i;
148         if(mod == NULL || mod->dev == NULL)
149                 return -1;
150
151         scxi_slot_select(mod->dev, mod->dio_subdev, mod->ser_subdev, mod->chassis, mod->slot);
152
153         scxi_serial_config(mod->dev, SLOW_INTERVAL);
154         local_serial_readwrite(mod->dev, mod->ser_subdev, 32, 0, &id);
155
156         if(id == 0xffffffff) {
157                 comedi_dio_write(mod->dev, mod->dio_subdev, SCXI_LINE_DA, 0);
158                 local_serial_readwrite(mod->dev, mod->ser_subdev, 32, 0, &id);
159                 comedi_dio_write(mod->dev, mod->dio_subdev, SCXI_LINE_DA, 1);
160         }
161
162         id = bswap_32(id);
163
164         scxi_module_deselect(mod);
165         
166         for (i=0;i<n_scxi_boards; i++) {
167                 if (id == scxi_boards[i].device_id) {
168                         mod->board = i;
169                         break;
170                 }
171         }
172
173         fprintf(stderr, "name=%s, device_id = 0x%x, chassis_ad = %d, mod = %d\n",
174                 scxi_boards[mod->board].name, scxi_boards[mod->board].device_id, mod->chassis, mod->slot);
175   
176         return 0;
177
178 }
179
180 int comedi_scxi_register_readwrite(scxi_mod_t *mod, unsigned short reg_address, unsigned int num_bytes,
181                             unsigned char *data_out, unsigned char *data_in)
182 {
183         unsigned int i;
184         unsigned int tmp_in, tmp_out = 0;
185
186         if(mod == NULL || mod->dev == NULL) return -1;
187
188         scxi_module_select(mod, reg_address);
189
190         for(i = 0; i < num_bytes; ++i) {
191                 if(data_out) tmp_out = data_out[i];
192                 local_serial_readwrite(mod->dev, mod->ser_subdev, 8, tmp_out, &tmp_in);
193                 if(data_in) data_in[i] = tmp_in;
194         }
195
196         if(scxi_boards[mod->board].modclass == 1 && reg_address == 0) {
197                 comedi_dio_write(mod->dev, mod->dio_subdev, SCXI_LINE_SS, 1);
198         }
199
200         scxi_module_deselect(mod);
201         return 0;
202 }