staging: comedi: add new device-global config interface
Adds interface for configuring options that are global to all sub-devices. For now, only options to configure device-globally identified signal routes have been defined. Signed-off-by: Spencer E. Olson <olsonse@umich.edu> Reviewed-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
5912827dfe
Коммит
d7569ad766
|
@ -107,6 +107,7 @@
|
|||
#define INSN_WRITE (1 | INSN_MASK_WRITE)
|
||||
#define INSN_BITS (2 | INSN_MASK_READ | INSN_MASK_WRITE)
|
||||
#define INSN_CONFIG (3 | INSN_MASK_READ | INSN_MASK_WRITE)
|
||||
#define INSN_DEVICE_CONFIG (INSN_CONFIG | INSN_MASK_SPECIAL)
|
||||
#define INSN_GTOD (4 | INSN_MASK_READ | INSN_MASK_SPECIAL)
|
||||
#define INSN_WAIT (5 | INSN_MASK_WRITE | INSN_MASK_SPECIAL)
|
||||
#define INSN_INTTRIG (6 | INSN_MASK_WRITE | INSN_MASK_SPECIAL)
|
||||
|
@ -350,6 +351,23 @@ enum configuration_ids {
|
|||
INSN_CONFIG_GET_CMD_TIMING_CONSTRAINTS = 5005,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum device_configuration_ids - COMEDI configuration instruction codes global
|
||||
* to an entire device.
|
||||
* @INSN_DEVICE_CONFIG_TEST_ROUTE: Validate the possibility of a
|
||||
* globally-named route
|
||||
* @INSN_DEVICE_CONFIG_CONNECT_ROUTE: Connect a globally-named route
|
||||
* @INSN_DEVICE_CONFIG_DISCONNECT_ROUTE:Disconnect a globally-named route
|
||||
* @INSN_DEVICE_CONFIG_GET_ROUTES: Get a list of all globally-named routes
|
||||
* that are valid for a particular device.
|
||||
*/
|
||||
enum device_config_route_ids {
|
||||
INSN_DEVICE_CONFIG_TEST_ROUTE = 0,
|
||||
INSN_DEVICE_CONFIG_CONNECT_ROUTE = 1,
|
||||
INSN_DEVICE_CONFIG_DISCONNECT_ROUTE = 2,
|
||||
INSN_DEVICE_CONFIG_GET_ROUTES = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum comedi_digital_trig_op - operations for configuring a digital trigger
|
||||
* @COMEDI_DIGITAL_TRIG_DISABLE: Return digital trigger to its default,
|
||||
|
|
|
@ -1234,6 +1234,57 @@ static int check_insn_config_length(struct comedi_insn *insn,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int check_insn_device_config_length(struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
if (insn->n < 1)
|
||||
return -EINVAL;
|
||||
|
||||
switch (data[0]) {
|
||||
case INSN_DEVICE_CONFIG_TEST_ROUTE:
|
||||
case INSN_DEVICE_CONFIG_CONNECT_ROUTE:
|
||||
case INSN_DEVICE_CONFIG_DISCONNECT_ROUTE:
|
||||
if (insn->n == 3)
|
||||
return 0;
|
||||
break;
|
||||
case INSN_DEVICE_CONFIG_GET_ROUTES:
|
||||
/*
|
||||
* Big enough for config_id and the length of the userland
|
||||
* memory buffer. Additional length should be in factors of 2
|
||||
* to communicate any returned route pairs (source,destination).
|
||||
*/
|
||||
if (insn->n >= 2)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_valid_routes() - Calls low-level driver get_valid_routes function to
|
||||
* either return a count of valid routes to user, or copy
|
||||
* of list of all valid device routes to buffer in
|
||||
* userspace.
|
||||
* @dev: comedi device pointer
|
||||
* @data: data from user insn call. The length of the data must be >= 2.
|
||||
* data[0] must contain the INSN_DEVICE_CONFIG config_id.
|
||||
* data[1](input) contains the number of _pairs_ for which memory is
|
||||
* allotted from the user. If the user specifies '0', then only
|
||||
* the number of pairs available is returned.
|
||||
* data[1](output) returns either the number of pairs available (if none
|
||||
* where requested) or the number of _pairs_ that are copied back
|
||||
* to the user.
|
||||
* data[2::2] returns each (source, destination) pair.
|
||||
*
|
||||
* Return: -EINVAL if low-level driver does not allocate and return routes as
|
||||
* expected. Returns 0 otherwise.
|
||||
*/
|
||||
static int get_valid_routes(struct comedi_device *dev, unsigned int *data)
|
||||
{
|
||||
data[1] = dev->get_valid_routes(dev, data[1], data + 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
|
||||
unsigned int *data, void *file)
|
||||
{
|
||||
|
@ -1297,6 +1348,24 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
|
|||
if (ret >= 0)
|
||||
ret = 1;
|
||||
break;
|
||||
case INSN_DEVICE_CONFIG:
|
||||
ret = check_insn_device_config_length(insn, data);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (data[0] == INSN_DEVICE_CONFIG_GET_ROUTES) {
|
||||
/*
|
||||
* data[1] should be the number of _pairs_ that
|
||||
* the memory can hold.
|
||||
*/
|
||||
data[1] = (insn->n - 2) / 2;
|
||||
ret = get_valid_routes(dev, data);
|
||||
break;
|
||||
}
|
||||
|
||||
/* other global device config instructions. */
|
||||
ret = dev->insn_device_config(dev, insn, data);
|
||||
break;
|
||||
default:
|
||||
dev_dbg(dev->class_dev, "invalid insn\n");
|
||||
ret = -EINVAL;
|
||||
|
|
|
@ -516,6 +516,15 @@ struct comedi_driver {
|
|||
* called when @use_count changes from 0 to 1.
|
||||
* @close: Optional pointer to a function set by the low-level driver to be
|
||||
* called when @use_count changed from 1 to 0.
|
||||
* @insn_device_config: Optional pointer to a handler for all sub-instructions
|
||||
* except %INSN_DEVICE_CONFIG_GET_ROUTES of the %INSN_DEVICE_CONFIG
|
||||
* instruction. If this is not initialized by the low-level driver, a
|
||||
* default handler will be set during post-configuration.
|
||||
* @get_valid_routes: Optional pointer to a handler for the
|
||||
* %INSN_DEVICE_CONFIG_GET_ROUTES sub-instruction of the
|
||||
* %INSN_DEVICE_CONFIG instruction set. If this is not initialized by the
|
||||
* low-level driver, a default handler that copies zero routes back to the
|
||||
* user will be used.
|
||||
*
|
||||
* This is the main control data structure for a COMEDI device (as far as the
|
||||
* COMEDI core is concerned). There are two groups of COMEDI devices -
|
||||
|
@ -565,6 +574,11 @@ struct comedi_device {
|
|||
|
||||
int (*open)(struct comedi_device *dev);
|
||||
void (*close)(struct comedi_device *dev);
|
||||
int (*insn_device_config)(struct comedi_device *dev,
|
||||
struct comedi_insn *insn, unsigned int *data);
|
||||
unsigned int (*get_valid_routes)(struct comedi_device *dev,
|
||||
unsigned int n_pairs,
|
||||
unsigned int *pair_data);
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -211,6 +211,19 @@ static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int insn_device_inval(struct comedi_device *dev,
|
||||
struct comedi_insn *insn, unsigned int *data)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static unsigned int get_zero_valid_routes(struct comedi_device *dev,
|
||||
unsigned int n_pairs,
|
||||
unsigned int *pair_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn, unsigned int *data)
|
||||
{
|
||||
|
@ -652,6 +665,12 @@ static int __comedi_device_postconfig(struct comedi_device *dev)
|
|||
int ret;
|
||||
int i;
|
||||
|
||||
if (!dev->insn_device_config)
|
||||
dev->insn_device_config = insn_device_inval;
|
||||
|
||||
if (!dev->get_valid_routes)
|
||||
dev->get_valid_routes = get_zero_valid_routes;
|
||||
|
||||
for (i = 0; i < dev->n_subdevices; i++) {
|
||||
s = &dev->subdevices[i];
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче