1 /* SPDX-License-Identifier: GPL-2.0+ */ 2 /* vim: set ts=8 sw=8 noet tw=80 nowrap: */ 3 /* 4 * comedi/drivers/ni_routes.h 5 * Route information for NI boards. 6 * 7 * COMEDI - Linux Control and Measurement Device Interface 8 * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 */ 20 21 #ifndef _COMEDI_DRIVERS_NI_ROUTES_H 22 #define _COMEDI_DRIVERS_NI_ROUTES_H 23 24 #include <linux/types.h> 25 #include <linux/errno.h> 26 27 #ifndef NI_ROUTE_VALUE_EXTERNAL_CONVERSION 28 #include <linux/bitops.h> 29 #endif 30 31 #include "../comedi.h" 32 33 /** 34 * struct ni_route_set - Set of destinations with a common source. 35 * @dest: Destination of all sources in this route set. 36 * @n_src: Number of sources for this route set. 37 * @src: List of sources that all map to the same destination. 38 */ 39 struct ni_route_set { 40 int dest; 41 int n_src; 42 int *src; 43 }; 44 45 /** 46 * struct ni_device_routes - List of all src->dest sets for a particular device. 47 * @device: Name of board/device (e.g. pxi-6733). 48 * @n_route_sets: Number of route sets that are valid for this device. 49 * @routes: List of route sets that are valid for this device. 50 */ 51 struct ni_device_routes { 52 const char *device; 53 int n_route_sets; 54 struct ni_route_set *routes; 55 }; 56 57 /** 58 * struct ni_route_tables - Register values and valid routes for a device. 59 * @valid_routes: Pointer to a all valid route sets for a single device. 60 * @route_values: Pointer to register values for all routes for the family to 61 * which the device belongs. 62 * 63 * Link to the valid src->dest routes and the register values used to assign 64 * such routes for that particular device. 65 */ 66 struct ni_route_tables { 67 const struct ni_device_routes *valid_routes; 68 const u8 *route_values; 69 }; 70 71 /* 72 * ni_assign_device_routes() - Assign the proper lookup table for NI signal 73 * routing to the specified NI device. 74 * 75 * Return: -ENODATA if assignment was not successful; 0 if successful. 76 */ 77 int ni_assign_device_routes(const char *device_family, 78 const char *board_name, 79 const char *alt_board_name, 80 struct ni_route_tables *tables); 81 82 /* 83 * ni_find_route_set() - Finds the proper route set with the specified 84 * destination. 85 * @destination: Destination of which to search for the route set. 86 * @valid_routes: Pointer to device routes within which to search. 87 * 88 * Return: NULL if no route_set is found with the specified @destination; 89 * otherwise, a pointer to the route_set if found. 90 */ 91 const struct ni_route_set * 92 ni_find_route_set(const int destination, 93 const struct ni_device_routes *valid_routes); 94 95 /* 96 * ni_route_set_has_source() - Determines whether the given source is in 97 * included given route_set. 98 * 99 * Return: true if found; false otherwise. 100 */ 101 bool ni_route_set_has_source(const struct ni_route_set *routes, const int src); 102 103 /* 104 * ni_route_to_register() - Validates and converts the specified signal route 105 * (src-->dest) to the value used at the appropriate 106 * register. 107 * @src: global-identifier for route source 108 * @dest: global-identifier for route destination 109 * @tables: pointer to relevant set of routing tables. 110 * 111 * Generally speaking, most routes require the first six bits and a few require 112 * 7 bits. Special handling is given for the return value when the route is to 113 * be handled by the RTSI sub-device. In this case, the returned register may 114 * not be sufficient to define the entire route path, but rather may only 115 * indicate the intermediate route. For example, if the route must go through 116 * the RGOUT0 pin, the (src->RGOUT0) register value will be returned. 117 * Similarly, if the route must go through the NI_RTSI_BRD lines, the BIT(6) 118 * will be set: 119 * 120 * if route does not need RTSI_BRD lines: 121 * bits 0:7 : register value 122 * for a route that must go through RGOUT0 pin, this will be equal 123 * to the (src->RGOUT0) register value. 124 * else: * route is (src->RTSI_BRD(x), RTSI_BRD(x)->TRIGGER_LINE(i)) * 125 * bits 0:5 : zero 126 * bits 6 : set to 1 127 * bits 7:7 : zero 128 * 129 * Return: register value to be used for source at destination with special 130 * cases given above; Otherwise, -1 if the specified route is not valid for 131 * this particular device. 132 */ 133 s8 ni_route_to_register(const int src, const int dest, 134 const struct ni_route_tables *tables); 135 136 static inline bool ni_rtsi_route_requires_mux(s8 value) 137 { 138 return value & BIT(6); 139 } 140 141 /* 142 * ni_lookup_route_register() - Look up a register value for a particular route 143 * without checking whether the route is valid for 144 * the particular device. 145 * @src: global-identifier for route source 146 * @dest: global-identifier for route destination 147 * @tables: pointer to relevant set of routing tables. 148 * 149 * Return: -EINVAL if the specified route is not valid for this device family. 150 */ 151 s8 ni_lookup_route_register(int src, int dest, 152 const struct ni_route_tables *tables); 153 154 /** 155 * route_is_valid() - Determines whether the specified signal route (src-->dest) 156 * is valid for the given NI comedi_device. 157 * @src: global-identifier for route source 158 * @dest: global-identifier for route destination 159 * @tables: pointer to relevant set of routing tables. 160 * 161 * Return: True if the route is valid, otherwise false. 162 */ 163 static inline bool route_is_valid(const int src, const int dest, 164 const struct ni_route_tables *tables) 165 { 166 return ni_route_to_register(src, dest, tables) >= 0; 167 } 168 169 /* 170 * ni_is_cmd_dest() - Determine whether the given destination is only 171 * configurable via a comedi_cmd struct. 172 * @dest: Destination to test. 173 */ 174 bool ni_is_cmd_dest(int dest); 175 176 static inline bool channel_is_pfi(int channel) 177 { 178 return NI_PFI(0) <= channel && channel <= NI_PFI(-1); 179 } 180 181 static inline bool channel_is_rtsi(int channel) 182 { 183 return TRIGGER_LINE(0) <= channel && channel <= TRIGGER_LINE(-1); 184 } 185 186 static inline bool channel_is_ctr(int channel) 187 { 188 return channel >= NI_COUNTER_NAMES_BASE && 189 channel <= NI_COUNTER_NAMES_MAX; 190 } 191 192 /* 193 * ni_count_valid_routes() - Count the number of valid routes. 194 * @tables: Routing tables for which to count all valid routes. 195 */ 196 unsigned int ni_count_valid_routes(const struct ni_route_tables *tables); 197 198 /* 199 * ni_get_valid_routes() - Implements INSN_DEVICE_CONFIG_GET_ROUTES. 200 * @tables: pointer to relevant set of routing tables. 201 * @n_pairs: Number of pairs for which memory is allocated by the user. If 202 * the user specifies '0', only the number of available pairs is 203 * returned. 204 * @pair_data: Pointer to memory allocated to return pairs back to user. Each 205 * even, odd indexed member of this array will hold source, 206 * destination of a route pair respectively. 207 * 208 * Return: the number of valid routes if n_pairs == 0; otherwise, the number of 209 * valid routes copied. 210 */ 211 unsigned int ni_get_valid_routes(const struct ni_route_tables *tables, 212 unsigned int n_pairs, 213 unsigned int *pair_data); 214 215 /* 216 * ni_sort_device_routes() - Sort the list of valid device signal routes in 217 * preparation for use. 218 * @valid_routes: pointer to ni_device_routes struct to sort. 219 */ 220 void ni_sort_device_routes(struct ni_device_routes *valid_routes); 221 222 /* 223 * ni_find_route_source() - Finds the signal source corresponding to a signal 224 * route (src-->dest) of the specified routing register 225 * value and the specified route destination on the 226 * specified device. 227 * 228 * Note that this function does _not_ validate the source based on device 229 * routes. 230 * 231 * Return: The NI signal value (e.g. NI_PFI(0) or PXI_Clk10) if found. 232 * If the source was not found (i.e. the register value is not 233 * valid for any routes to the destination), -EINVAL is returned. 234 */ 235 int ni_find_route_source(const u8 src_sel_reg_value, const int dest, 236 const struct ni_route_tables *tables); 237 238 /** 239 * route_register_is_valid() - Determines whether the register value for the 240 * specified route destination on the specified 241 * device is valid. 242 */ 243 static inline bool route_register_is_valid(const u8 src_sel_reg_value, 244 const int dest, 245 const struct ni_route_tables *tables) 246 { 247 return ni_find_route_source(src_sel_reg_value, dest, tables) >= 0; 248 } 249 250 /** 251 * ni_get_reg_value_roffs() - Determines the proper register value for a 252 * particular valid NI signal/terminal route. 253 * @src: Either a direct register value or one of NI_* signal names. 254 * @dest: global-identifier for route destination 255 * @tables: pointer to relevant set of routing tables. 256 * @direct_reg_offset: 257 * Compatibility compensation argument. This argument allows us to 258 * arbitrarily apply an offset to src if src is a direct register 259 * value reference. This is necessary to be compatible with 260 * definitions of register values as previously exported directly 261 * to user space. 262 * 263 * Return: the register value (>0) to be used at the destination if the src is 264 * valid for the given destination; -1 otherwise. 265 */ 266 static inline s8 ni_get_reg_value_roffs(int src, const int dest, 267 const struct ni_route_tables *tables, 268 const int direct_reg_offset) 269 { 270 if (src < NI_NAMES_BASE) { 271 src += direct_reg_offset; 272 /* 273 * In this case, the src is expected to actually be a register 274 * value. 275 */ 276 if (route_register_is_valid(src, dest, tables)) 277 return src; 278 return -1; 279 } 280 281 /* 282 * Otherwise, the src is expected to be one of the abstracted NI 283 * signal/terminal names. 284 */ 285 return ni_route_to_register(src, dest, tables); 286 } 287 288 static inline int ni_get_reg_value(const int src, const int dest, 289 const struct ni_route_tables *tables) 290 { 291 return ni_get_reg_value_roffs(src, dest, tables, 0); 292 } 293 294 /** 295 * ni_check_trigger_arg_roffs() - Checks the trigger argument (*_arg) of an NI 296 * device to ensure that the *_arg value 297 * corresponds to _either_ a valid register value 298 * to define a trigger source, _or_ a valid NI 299 * signal/terminal name that has a valid route to 300 * the destination on the particular device. 301 * @src: Either a direct register value or one of NI_* signal names. 302 * @dest: global-identifier for route destination 303 * @tables: pointer to relevant set of routing tables. 304 * @direct_reg_offset: 305 * Compatibility compensation argument. This argument allows us to 306 * arbitrarily apply an offset to src if src is a direct register 307 * value reference. This is necessary to be compatible with 308 * definitions of register values as previously exported directly 309 * to user space. 310 * 311 * Return: 0 if the src (either register value or NI signal/terminal name) is 312 * valid for the destination; -EINVAL otherwise. 313 */ 314 static inline 315 int ni_check_trigger_arg_roffs(int src, const int dest, 316 const struct ni_route_tables *tables, 317 const int direct_reg_offset) 318 { 319 if (ni_get_reg_value_roffs(src, dest, tables, direct_reg_offset) < 0) 320 return -EINVAL; 321 return 0; 322 } 323 324 static inline int ni_check_trigger_arg(const int src, const int dest, 325 const struct ni_route_tables *tables) 326 { 327 return ni_check_trigger_arg_roffs(src, dest, tables, 0); 328 } 329 330 #endif /* _COMEDI_DRIVERS_NI_ROUTES_H */ 331