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