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