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