1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include <linux/module.h>
22#include <linux/slab.h>
23#include <linux/bsearch.h>
24#include <linux/sort.h>
25
26#include "../comedi.h"
27
28#include "ni_routes.h"
29#include "ni_routing/ni_route_values.h"
30#include "ni_routing/ni_device_routes.h"
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50#define RVi(table, src, dest) ((table)[(dest) * NI_NUM_NAMES + (src)])
51
52static const size_t route_table_size = NI_NUM_NAMES * NI_NUM_NAMES;
53
54
55
56
57
58
59
60static int ni_find_device_routes(const char *device_family,
61 const char *board_name,
62 struct ni_route_tables *tables)
63{
64 const struct ni_device_routes *dr = NULL;
65 const u8 *rv = NULL;
66 int i;
67
68
69 for (i = 0; ni_all_route_values[i]; ++i) {
70 if (memcmp(ni_all_route_values[i]->family, device_family,
71 strnlen(device_family, 30)) == 0) {
72 rv = &ni_all_route_values[i]->register_values[0][0];
73 break;
74 }
75 }
76
77 if (!rv)
78 return -ENODATA;
79
80
81 for (i = 0; ni_device_routes_list[i]; ++i) {
82 if (memcmp(ni_device_routes_list[i]->device, board_name,
83 strnlen(board_name, 30)) == 0) {
84 dr = ni_device_routes_list[i];
85 break;
86 }
87 }
88
89 if (!dr)
90 return -ENODATA;
91
92 tables->route_values = rv;
93 tables->valid_routes = dr;
94
95 return 0;
96}
97
98
99
100
101
102
103
104int ni_assign_device_routes(const char *device_family,
105 const char *board_name,
106 struct ni_route_tables *tables)
107{
108 memset(tables, 0, sizeof(struct ni_route_tables));
109 return ni_find_device_routes(device_family, board_name, tables);
110}
111EXPORT_SYMBOL_GPL(ni_assign_device_routes);
112
113
114
115
116
117unsigned int ni_count_valid_routes(const struct ni_route_tables *tables)
118{
119 int total = 0;
120 int i;
121
122 for (i = 0; i < tables->valid_routes->n_route_sets; ++i) {
123 const struct ni_route_set *R = &tables->valid_routes->routes[i];
124 int j;
125
126 for (j = 0; j < R->n_src; ++j) {
127 const int src = R->src[j];
128 const int dest = R->dest;
129 const u8 *rv = tables->route_values;
130
131 if (RVi(rv, B(src), B(dest)))
132
133 ++total;
134 else if (channel_is_rtsi(dest) &&
135 (RVi(rv, B(src), B(NI_RGOUT0)) ||
136 RVi(rv, B(src), B(NI_RTSI_BRD(0))) ||
137 RVi(rv, B(src), B(NI_RTSI_BRD(1))) ||
138 RVi(rv, B(src), B(NI_RTSI_BRD(2))) ||
139 RVi(rv, B(src), B(NI_RTSI_BRD(3))))) {
140 ++total;
141 }
142 }
143 }
144 return total;
145}
146EXPORT_SYMBOL_GPL(ni_count_valid_routes);
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161unsigned int ni_get_valid_routes(const struct ni_route_tables *tables,
162 unsigned int n_pairs,
163 unsigned int *pair_data)
164{
165 unsigned int n_valid = ni_count_valid_routes(tables);
166 int i;
167
168 if (n_pairs == 0 || n_valid == 0)
169 return n_valid;
170
171 if (!pair_data)
172 return 0;
173
174 n_valid = 0;
175
176 for (i = 0; i < tables->valid_routes->n_route_sets; ++i) {
177 const struct ni_route_set *R = &tables->valid_routes->routes[i];
178 int j;
179
180 for (j = 0; j < R->n_src; ++j) {
181 const int src = R->src[j];
182 const int dest = R->dest;
183 bool valid = false;
184 const u8 *rv = tables->route_values;
185
186 if (RVi(rv, B(src), B(dest)))
187
188 valid = true;
189 else if (channel_is_rtsi(dest) &&
190 (RVi(rv, B(src), B(NI_RGOUT0)) ||
191 RVi(rv, B(src), B(NI_RTSI_BRD(0))) ||
192 RVi(rv, B(src), B(NI_RTSI_BRD(1))) ||
193 RVi(rv, B(src), B(NI_RTSI_BRD(2))) ||
194 RVi(rv, B(src), B(NI_RTSI_BRD(3))))) {
195
196 valid = true;
197 }
198
199 if (valid) {
200 pair_data[2 * n_valid] = src;
201 pair_data[2 * n_valid + 1] = dest;
202 ++n_valid;
203 }
204
205 if (n_valid >= n_pairs)
206 return n_valid;
207 }
208 }
209 return n_valid;
210}
211EXPORT_SYMBOL_GPL(ni_get_valid_routes);
212
213
214
215
216
217static const int NI_CMD_DESTS[] = {
218 NI_AI_SampleClock,
219 NI_AI_StartTrigger,
220 NI_AI_ConvertClock,
221 NI_AO_SampleClock,
222 NI_AO_StartTrigger,
223 NI_DI_SampleClock,
224 NI_DO_SampleClock,
225};
226
227
228
229
230
231
232bool ni_is_cmd_dest(int dest)
233{
234 int i;
235
236 for (i = 0; i < ARRAY_SIZE(NI_CMD_DESTS); ++i)
237 if (NI_CMD_DESTS[i] == dest)
238 return true;
239 return false;
240}
241EXPORT_SYMBOL_GPL(ni_is_cmd_dest);
242
243
244static int _ni_sort_destcmp(const void *va, const void *vb)
245{
246 const struct ni_route_set *a = va;
247 const struct ni_route_set *b = vb;
248
249 if (a->dest < b->dest)
250 return -1;
251 else if (a->dest > b->dest)
252 return 1;
253 return 0;
254}
255
256static int _ni_sort_srccmp(const void *vsrc0, const void *vsrc1)
257{
258 const int *src0 = vsrc0;
259 const int *src1 = vsrc1;
260
261 if (*src0 < *src1)
262 return -1;
263 else if (*src0 > *src1)
264 return 1;
265 return 0;
266}
267
268
269
270
271
272
273void ni_sort_device_routes(struct ni_device_routes *valid_routes)
274{
275 unsigned int n;
276
277
278 valid_routes->n_route_sets = 0;
279 while (valid_routes->routes[valid_routes->n_route_sets].dest != 0)
280 ++valid_routes->n_route_sets;
281
282
283 sort(valid_routes->routes, valid_routes->n_route_sets,
284 sizeof(struct ni_route_set), _ni_sort_destcmp, NULL);
285
286
287 for (n = 0; n < valid_routes->n_route_sets; ++n) {
288 struct ni_route_set *rs = &valid_routes->routes[n];
289
290
291 rs->n_src = 0;
292 while (rs->src[rs->n_src])
293 ++rs->n_src;
294
295
296 sort(valid_routes->routes[n].src, valid_routes->routes[n].n_src,
297 sizeof(int), _ni_sort_srccmp, NULL);
298 }
299}
300EXPORT_SYMBOL_GPL(ni_sort_device_routes);
301
302
303static void ni_sort_all_device_routes(void)
304{
305 unsigned int i;
306
307 for (i = 0; ni_device_routes_list[i]; ++i)
308 ni_sort_device_routes(ni_device_routes_list[i]);
309}
310
311
312static int _ni_bsearch_destcmp(const void *vkey, const void *velt)
313{
314 const int *key = vkey;
315 const struct ni_route_set *elt = velt;
316
317 if (*key < elt->dest)
318 return -1;
319 else if (*key > elt->dest)
320 return 1;
321 return 0;
322}
323
324static int _ni_bsearch_srccmp(const void *vkey, const void *velt)
325{
326 const int *key = vkey;
327 const int *elt = velt;
328
329 if (*key < *elt)
330 return -1;
331 else if (*key > *elt)
332 return 1;
333 return 0;
334}
335
336
337
338
339
340
341
342
343
344
345const struct ni_route_set *
346ni_find_route_set(const int destination,
347 const struct ni_device_routes *valid_routes)
348{
349 return bsearch(&destination, valid_routes->routes,
350 valid_routes->n_route_sets, sizeof(struct ni_route_set),
351 _ni_bsearch_destcmp);
352}
353EXPORT_SYMBOL_GPL(ni_find_route_set);
354
355
356
357
358
359
360
361bool ni_route_set_has_source(const struct ni_route_set *routes,
362 const int source)
363{
364 if (!bsearch(&source, routes->src, routes->n_src, sizeof(int),
365 _ni_bsearch_srccmp))
366 return false;
367 return true;
368}
369EXPORT_SYMBOL_GPL(ni_route_set_has_source);
370
371
372
373
374
375
376
377
378
379
380
381s8 ni_lookup_route_register(int src, int dest,
382 const struct ni_route_tables *tables)
383{
384 s8 regval;
385
386
387
388
389
390 src = B(src);
391 dest = B(dest);
392 if (src < 0 || src >= NI_NUM_NAMES || dest < 0 || dest >= NI_NUM_NAMES)
393 return -EINVAL;
394 regval = RVi(tables->route_values, src, dest);
395 if (!regval)
396 return -EINVAL;
397
398 return UNMARK(regval);
399}
400EXPORT_SYMBOL_GPL(ni_lookup_route_register);
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432s8 ni_route_to_register(const int src, const int dest,
433 const struct ni_route_tables *tables)
434{
435 const struct ni_route_set *routes =
436 ni_find_route_set(dest, tables->valid_routes);
437 const u8 *rv;
438 s8 regval;
439
440
441 if (!routes)
442 return -1;
443
444 if (!ni_route_set_has_source(routes, src))
445 return -1;
446
447
448
449
450
451 rv = tables->route_values;
452 regval = RVi(rv, B(src), B(dest));
453
454
455
456
457
458 if (!regval && channel_is_rtsi(dest)) {
459 regval = RVi(rv, B(src), B(NI_RGOUT0));
460 if (!regval && (RVi(rv, B(src), B(NI_RTSI_BRD(0))) ||
461 RVi(rv, B(src), B(NI_RTSI_BRD(1))) ||
462 RVi(rv, B(src), B(NI_RTSI_BRD(2))) ||
463 RVi(rv, B(src), B(NI_RTSI_BRD(3)))))
464 regval = BIT(6);
465 }
466
467 if (!regval)
468 return -1;
469
470 return UNMARK(regval);
471}
472EXPORT_SYMBOL_GPL(ni_route_to_register);
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487int ni_find_route_source(const u8 src_sel_reg_value, int dest,
488 const struct ni_route_tables *tables)
489{
490 int src;
491
492 dest = B(dest);
493
494 if (dest < 0 || dest >= NI_NUM_NAMES)
495 return -EINVAL;
496 for (src = 0; src < NI_NUM_NAMES; ++src)
497 if (RVi(tables->route_values, src, dest) ==
498 V(src_sel_reg_value))
499 return src + NI_NAMES_BASE;
500 return -EINVAL;
501}
502EXPORT_SYMBOL_GPL(ni_find_route_source);
503
504
505
506
507static int __init ni_routes_module_init(void)
508{
509 ni_sort_all_device_routes();
510 return 0;
511}
512
513static void __exit ni_routes_module_exit(void)
514{
515}
516
517module_init(ni_routes_module_init);
518module_exit(ni_routes_module_exit);
519
520MODULE_AUTHOR("Comedi http://www.comedi.org");
521MODULE_DESCRIPTION("Comedi helper for routing signals-->terminals for NI");
522MODULE_LICENSE("GPL");
523
524