Merge branch 'devel-1.6' into ethercat-backport_setip

This commit is contained in:
Florian Pose
2024-02-01 12:41:38 +01:00
339 changed files with 437071 additions and 114 deletions
+7 -2
View File
@@ -56,6 +56,11 @@
/*****************************************************************************/
enum {
/* genet driver needs extra headroom in skb for status block */
EXTRA_HEADROOM = 64,
};
/** Constructor.
*
* \return 0 in case of success, else < 0
@@ -127,14 +132,14 @@ int ec_device_init(
#endif
for (i = 0; i < EC_TX_RING_SIZE; i++) {
if (!(device->tx_skb[i] = dev_alloc_skb(ETH_FRAME_LEN))) {
if (!(device->tx_skb[i] = dev_alloc_skb(ETH_FRAME_LEN + EXTRA_HEADROOM))) {
EC_MASTER_ERR(master, "Error allocating device socket buffer!\n");
ret = -ENOMEM;
goto out_tx_ring;
}
// add Ethernet-II-header
skb_reserve(device->tx_skb[i], ETH_HLEN);
skb_reserve(device->tx_skb[i], ETH_HLEN + EXTRA_HEADROOM);
eth = (struct ethhdr *) skb_push(device->tx_skb[i], ETH_HLEN);
eth->h_proto = htons(0x88A4);
memset(eth->h_dest, 0xFF, ETH_ALEN);
+99 -18
View File
@@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
@@ -66,6 +64,7 @@ void ec_fsm_master_state_assign_sii(ec_fsm_master_t *);
void ec_fsm_master_state_write_sii(ec_fsm_master_t *);
void ec_fsm_master_state_sdo_dictionary(ec_fsm_master_t *);
void ec_fsm_master_state_sdo_request(ec_fsm_master_t *);
void ec_fsm_master_state_soe_request(ec_fsm_master_t *);
void ec_fsm_master_enter_clear_addresses(ec_fsm_master_t *);
void ec_fsm_master_enter_write_system_times(ec_fsm_master_t *);
@@ -83,8 +82,18 @@ void ec_fsm_master_init(
fsm->master = master;
fsm->datagram = datagram;
// inits the member variables state, idle, dev_idx, link_state,
// slaves_responding, slave_states and rescan_required
ec_fsm_master_reset(fsm);
fsm->retries = 0;
fsm->scan_jiffies = 0;
fsm->slave = NULL;
fsm->sii_request = NULL;
fsm->sii_index = 0;
fsm->sdo_request = NULL;
fsm->soe_request = NULL;
// init sub-state-machines
ec_fsm_coe_init(&fsm->fsm_coe);
ec_fsm_soe_init(&fsm->fsm_soe);
@@ -492,17 +501,18 @@ int ec_fsm_master_action_process_sii(
/*****************************************************************************/
/** Check for pending SDO requests and process one.
/** Check for pending internal SDO/SoE requests and process one.
*
* \return non-zero, if an SDO request is processed.
*/
int ec_fsm_master_action_process_sdo(
int ec_fsm_master_action_process_int_request(
ec_fsm_master_t *fsm /**< Master state machine. */
)
{
ec_master_t *master = fsm->master;
ec_slave_t *slave;
ec_sdo_request_t *req;
ec_sdo_request_t *sdo_req;
ec_soe_request_t *soe_req;
// search for internal requests to be processed
for (slave = master->slaves;
@@ -513,33 +523,61 @@ int ec_fsm_master_action_process_sdo(
continue;
}
list_for_each_entry(req, &slave->config->sdo_requests, list) {
if (req->state == EC_INT_REQUEST_QUEUED) {
list_for_each_entry(sdo_req, &slave->config->sdo_requests, list) {
if (sdo_req->state == EC_INT_REQUEST_QUEUED) {
if (ec_sdo_request_timed_out(req)) {
req->state = EC_INT_REQUEST_FAILURE;
if (ec_sdo_request_timed_out(sdo_req)) {
sdo_req->state = EC_INT_REQUEST_FAILURE;
EC_SLAVE_DBG(slave, 1, "Internal SDO request"
" timed out.\n");
continue;
}
if (slave->current_state == EC_SLAVE_STATE_INIT) {
req->state = EC_INT_REQUEST_FAILURE;
sdo_req->state = EC_INT_REQUEST_FAILURE;
continue;
}
req->state = EC_INT_REQUEST_BUSY;
sdo_req->state = EC_INT_REQUEST_BUSY;
EC_SLAVE_DBG(slave, 1, "Processing internal"
" SDO request...\n");
fsm->idle = 0;
fsm->sdo_request = req;
fsm->sdo_request = sdo_req;
fsm->slave = slave;
fsm->state = ec_fsm_master_state_sdo_request;
ec_fsm_coe_transfer(&fsm->fsm_coe, slave, req);
ec_fsm_coe_transfer(&fsm->fsm_coe, slave, sdo_req);
ec_fsm_coe_exec(&fsm->fsm_coe, fsm->datagram);
return 1;
}
}
list_for_each_entry(soe_req, &slave->config->soe_requests, list) {
if (soe_req->state == EC_INT_REQUEST_QUEUED) {
if (ec_soe_request_timed_out(soe_req)) {
soe_req->state = EC_INT_REQUEST_FAILURE;
EC_SLAVE_DBG(slave, 1, "Internal SoE request"
" timed out.\n");
continue;
}
if (slave->current_state == EC_SLAVE_STATE_INIT) {
soe_req->state = EC_INT_REQUEST_FAILURE;
continue;
}
soe_req->state = EC_INT_REQUEST_BUSY;
EC_SLAVE_DBG(slave, 1, "Processing internal"
" SoE request...\n");
fsm->idle = 0;
fsm->soe_request = soe_req;
fsm->slave = slave;
fsm->state = ec_fsm_master_state_soe_request;
ec_fsm_soe_transfer(&fsm->fsm_soe, slave, soe_req);
ec_fsm_soe_exec(&fsm->fsm_soe, fsm->datagram);
return 1;
}
}
}
return 0;
}
@@ -557,8 +595,8 @@ void ec_fsm_master_action_idle(
ec_master_t *master = fsm->master;
ec_slave_t *slave;
// Check for pending internal SDO requests
if (ec_fsm_master_action_process_sdo(fsm)) {
// Check for pending internal SDO or SoE requests
if (ec_fsm_master_action_process_int_request(fsm)) {
return;
}
@@ -1357,8 +1395,51 @@ void ec_fsm_master_state_sdo_request(
EC_SLAVE_DBG(fsm->slave, 1, "Finished internal SDO request.\n");
// check for another SDO request
if (ec_fsm_master_action_process_sdo(fsm)) {
// check for another SDO/SoE request
if (ec_fsm_master_action_process_int_request(fsm)) {
return; // processing another request
}
ec_fsm_master_restart(fsm);
}
/*****************************************************************************/
/** Master state: SoE REQUEST.
*/
void ec_fsm_master_state_soe_request(
ec_fsm_master_t *fsm /**< Master state machine. */
)
{
ec_soe_request_t *request = fsm->soe_request;
if (!request) {
// configuration was cleared in the meantime
ec_fsm_master_restart(fsm);
return;
}
if (ec_fsm_soe_exec(&fsm->fsm_soe, fsm->datagram)) {
return;
}
if (!ec_fsm_soe_success(&fsm->fsm_soe)) {
EC_SLAVE_DBG(fsm->slave, 1,
"Failed to process internal SoE request.\n");
request->state = EC_INT_REQUEST_FAILURE;
wake_up_all(&fsm->master->request_queue);
ec_fsm_master_restart(fsm);
return;
}
// SoE request finished
request->state = EC_INT_REQUEST_SUCCESS;
wake_up_all(&fsm->master->request_queue);
EC_SLAVE_DBG(fsm->slave, 1, "Finished internal SoE request.\n");
// check for another CoE/SoE request
if (ec_fsm_master_action_process_int_request(fsm)) {
return; // processing another request
}
+2 -3
View File
@@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
@@ -88,6 +86,7 @@ struct ec_fsm_master {
ec_sii_write_request_t *sii_request; /**< SII write request */
off_t sii_index; /**< index to SII write request data */
ec_sdo_request_t *sdo_request; /**< SDO request to process. */
ec_soe_request_t *soe_request; /**< SoE request to process. */
ec_fsm_coe_t fsm_coe; /**< CoE state machine */
ec_fsm_soe_t fsm_soe; /**< SoE state machine */
+1 -3
View File
@@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
+60 -5
View File
@@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
@@ -85,6 +83,7 @@ void ec_fsm_slave_config_state_dc_cycle(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_dc_sync_check(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_dc_start(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_dc_assign(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_wait_safeop(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_safeop(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_soe_conf_safeop(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_op(ec_fsm_slave_config_t *);
@@ -105,6 +104,7 @@ void ec_fsm_slave_config_enter_watchdog(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_enter_pdo_sync(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_enter_fmmu(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_enter_dc_cycle(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_enter_wait_safeop(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_enter_safeop(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_enter_soe_conf_safeop(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_enter_op(ec_fsm_slave_config_t *);
@@ -135,6 +135,8 @@ void ec_fsm_slave_config_init(
fsm->fsm_coe = fsm_coe;
fsm->fsm_soe = fsm_soe;
fsm->fsm_pdo = fsm_pdo;
fsm->wait_ms = 0;
}
/*****************************************************************************/
@@ -1224,7 +1226,7 @@ void ec_fsm_slave_config_enter_fmmu(
const ec_sync_t *sync;
if (!slave->config) {
ec_fsm_slave_config_enter_safeop(fsm);
ec_fsm_slave_config_enter_wait_safeop(fsm);
return;
}
@@ -1329,7 +1331,7 @@ void ec_fsm_slave_config_enter_dc_cycle(
fsm->state = ec_fsm_slave_config_state_dc_cycle;
} else {
// DC are unused
ec_fsm_slave_config_enter_safeop(fsm);
ec_fsm_slave_config_enter_wait_safeop(fsm);
}
}
@@ -1551,6 +1553,59 @@ void ec_fsm_slave_config_state_dc_assign(
return;
}
ec_fsm_slave_config_enter_wait_safeop(fsm);
}
/*****************************************************************************/
/** Wait before SAFEOP transition.
*
* The feature flag WaitBeforeSAFEOPms can be used to add a wait time before
* going to SAFEOP. This can be used as a workaround for slaves that need some
* extra time for initialisation.
*/
void ec_fsm_slave_config_enter_wait_safeop(
ec_fsm_slave_config_t *fsm /**< slave state machine */
)
{
ec_slave_config_t *config = fsm->slave->config;
fsm->wait_ms = 0UL;
if (config) {
ec_flag_t *flag = ec_slave_config_find_flag(config,
"WaitBeforeSAFEOPms");
if (flag && flag->value > 0) {
fsm->wait_ms = (unsigned long) flag->value;
}
}
if (fsm->wait_ms > 0) {
fsm->state = ec_fsm_slave_config_state_wait_safeop;
/* dummy read */
ec_datagram_fprd(fsm->datagram, fsm->slave->station_address,
0x0600, 1);
fsm->jiffies_start = jiffies;
}
else {
ec_fsm_slave_config_enter_safeop(fsm);
}
}
/*****************************************************************************/
/** Slave configuration state: WAIT SAFEOP.
*/
void ec_fsm_slave_config_state_wait_safeop(
ec_fsm_slave_config_t *fsm /**< slave state machine */
)
{
unsigned long diff = jiffies - fsm->jiffies_start;
if (diff * 1000 / HZ < fsm->wait_ms) {
return;
}
ec_fsm_slave_config_enter_safeop(fsm);
}
+2 -3
View File
@@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
@@ -68,6 +66,7 @@ struct ec_fsm_slave_config
ec_soe_request_t soe_request_copy; /**< Copied SDO request. */
unsigned long jiffies_start; /**< For timeout calculations. */
unsigned int take_time; /**< Store jiffies after datagram reception. */
unsigned long wait_ms; /**< Wait time (used to wait before SAFEOP). */
};
/*****************************************************************************/
+346 -4
View File
@@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
@@ -1482,7 +1480,7 @@ static ATTRIBUTES int ec_ioctl_config_idn(
ioctl->drive_no = req->drive_no;
ioctl->idn = req->idn;
ioctl->state = req->state;
ioctl->state = req->al_state;
ioctl->size = req->data_size;
memcpy(ioctl->data, req->data,
min((u32) ioctl->size, (u32) EC_MAX_IDN_DATA_SIZE));
@@ -2906,6 +2904,59 @@ static ATTRIBUTES int ec_ioctl_sc_create_sdo_request(
/*****************************************************************************/
/** Create an SoE request.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_sc_create_soe_request(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
ec_ioctl_soe_request_t data;
ec_slave_config_t *sc;
ec_soe_request_t *req;
if (unlikely(!ctx->requested))
return -EPERM;
if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
return -EFAULT;
}
data.request_index = 0;
if (down_interruptible(&master->master_sem))
return -EINTR;
sc = ec_master_get_config(master, data.config_index);
if (!sc) {
up(&master->master_sem);
return -ENOENT;
}
list_for_each_entry(req, &sc->soe_requests, list) {
data.request_index++;
}
up(&master->master_sem); /** \todo sc could be invalidated */
req = ecrt_slave_config_create_soe_request_err(sc, data.drive_no,
data.idn, data.size);
if (IS_ERR(req)) {
return PTR_ERR(req);
}
if (copy_to_user((void __user *) arg, &data, sizeof(data))) {
return -EFAULT;
}
return 0;
}
/*****************************************************************************/
/** Create a register request.
*
* \return Zero on success, otherwise a negative error code.
@@ -3137,6 +3188,7 @@ static ATTRIBUTES int ec_ioctl_sc_flag(
kfree(key);
return -EFAULT;
}
key[ioctl.key_size] = '\0';
if (down_interruptible(&master->master_sem)) {
kfree(key);
@@ -3569,6 +3621,255 @@ static ATTRIBUTES int ec_ioctl_sdo_request_data(
/*****************************************************************************/
/** Sets an SoE request's drive number and IDN.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_soe_request_index(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
ec_ioctl_soe_request_t data;
ec_slave_config_t *sc;
ec_soe_request_t *req;
if (unlikely(!ctx->requested))
return -EPERM;
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
return -EFAULT;
/* no locking of master_sem needed, because neither sc nor req will not be
* deleted in the meantime. */
if (!(sc = ec_master_get_config(master, data.config_index))) {
return -ENOENT;
}
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
return -ENOENT;
}
ecrt_soe_request_idn(req, data.drive_no, data.idn);
return 0;
}
/*****************************************************************************/
/** Sets an CoE request's timeout.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_soe_request_timeout(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
ec_ioctl_soe_request_t data;
ec_slave_config_t *sc;
ec_soe_request_t *req;
if (unlikely(!ctx->requested))
return -EPERM;
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
return -EFAULT;
/* no locking of master_sem needed, because neither sc nor req will not be
* deleted in the meantime. */
if (!(sc = ec_master_get_config(master, data.config_index))) {
return -ENOENT;
}
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
return -ENOENT;
}
ecrt_soe_request_timeout(req, data.timeout);
return 0;
}
/*****************************************************************************/
/** Gets an SoE request's state.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_soe_request_state(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
ec_ioctl_soe_request_t data;
ec_slave_config_t *sc;
ec_soe_request_t *req;
if (unlikely(!ctx->requested))
return -EPERM;
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
return -EFAULT;
/* no locking of master_sem needed, because neither sc nor req will not be
* deleted in the meantime. */
if (!(sc = ec_master_get_config(master, data.config_index))) {
return -ENOENT;
}
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
return -ENOENT;
}
data.state = ecrt_soe_request_state(req);
if (data.state == EC_REQUEST_SUCCESS && req->dir == EC_DIR_INPUT) {
data.size = ecrt_soe_request_data_size(req);
}
else {
data.size = 0;
}
if (copy_to_user((void __user *) arg, &data, sizeof(data)))
return -EFAULT;
return 0;
}
/*****************************************************************************/
/** Starts an SoE IDN read operation.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_soe_request_read(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
ec_ioctl_soe_request_t data;
ec_slave_config_t *sc;
ec_soe_request_t *req;
if (unlikely(!ctx->requested))
return -EPERM;
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
return -EFAULT;
/* no locking of master_sem needed, because neither sc nor req will not be
* deleted in the meantime. */
if (!(sc = ec_master_get_config(master, data.config_index))) {
return -ENOENT;
}
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
return -ENOENT;
}
ecrt_soe_request_read(req);
return 0;
}
/*****************************************************************************/
/** Starts an SoE IDN write operation.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_soe_request_write(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
ec_ioctl_soe_request_t data;
ec_slave_config_t *sc;
ec_soe_request_t *req;
int ret;
if (unlikely(!ctx->requested))
return -EPERM;
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
return -EFAULT;
if (!data.size) {
EC_MASTER_ERR(master, "IDN write: Data size may not be zero!\n");
return -EINVAL;
}
/* no locking of master_sem needed, because neither sc nor req will not be
* deleted in the meantime. */
if (!(sc = ec_master_get_config(master, data.config_index))) {
return -ENOENT;
}
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
return -ENOENT;
}
ret = ec_soe_request_alloc(req, data.size);
if (ret)
return ret;
if (copy_from_user(req->data, (void __user *) data.data, data.size))
return -EFAULT;
req->data_size = data.size;
ecrt_soe_request_write(req);
return 0;
}
/*****************************************************************************/
/** Read SoE IDN data.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_soe_request_data(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
ec_ioctl_soe_request_t data;
ec_slave_config_t *sc;
ec_soe_request_t *req;
if (unlikely(!ctx->requested))
return -EPERM;
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
return -EFAULT;
/* no locking of master_sem needed, because neither sc nor req will not be
* deleted in the meantime. */
if (!(sc = ec_master_get_config(master, data.config_index))) {
return -ENOENT;
}
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
return -ENOENT;
}
if (copy_to_user((void __user *) data.data, ecrt_soe_request_data(req),
ecrt_soe_request_data_size(req)))
return -EFAULT;
return 0;
}
/*****************************************************************************/
/** Read register data.
*
* \return Zero on success, otherwise a negative error code.
@@ -4712,6 +5013,13 @@ long EC_IOCTL(
}
ret = ec_ioctl_sc_create_sdo_request(master, arg, ctx);
break;
case EC_IOCTL_SC_SOE_REQUEST:
if (!ctx->writable) {
ret = -EPERM;
break;
}
ret = ec_ioctl_sc_create_soe_request(master, arg, ctx);
break;
case EC_IOCTL_SC_REG_REQUEST:
if (!ctx->writable) {
ret = -EPERM;
@@ -4800,6 +5108,40 @@ long EC_IOCTL(
case EC_IOCTL_SDO_REQUEST_DATA:
ret = ec_ioctl_sdo_request_data(master, arg, ctx);
break;
case EC_IOCTL_SOE_REQUEST_IDN:
if (!ctx->writable) {
ret = -EPERM;
break;
}
ret = ec_ioctl_soe_request_index(master, arg, ctx);
break;
case EC_IOCTL_SOE_REQUEST_TIMEOUT:
if (!ctx->writable) {
ret = -EPERM;
break;
}
ret = ec_ioctl_soe_request_timeout(master, arg, ctx);
break;
case EC_IOCTL_SOE_REQUEST_STATE:
ret = ec_ioctl_soe_request_state(master, arg, ctx);
break;
case EC_IOCTL_SOE_REQUEST_READ:
if (!ctx->writable) {
ret = -EPERM;
break;
}
ret = ec_ioctl_soe_request_read(master, arg, ctx);
break;
case EC_IOCTL_SOE_REQUEST_WRITE:
if (!ctx->writable) {
ret = -EPERM;
break;
}
ret = ec_ioctl_soe_request_write(master, arg, ctx);
break;
case EC_IOCTL_SOE_REQUEST_DATA:
ret = ec_ioctl_soe_request_data(master, arg, ctx);
break;
case EC_IOCTL_REG_REQUEST_DATA:
ret = ec_ioctl_reg_request_data(master, arg, ctx);
break;
+52 -29
View File
@@ -47,7 +47,7 @@
*
* Increment this when changing the ioctl interface!
*/
#define EC_IOCTL_VERSION_MAGIC 33
#define EC_IOCTL_VERSION_MAGIC 34
// Command-line tool
#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)
@@ -121,34 +121,41 @@
#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x3e, ec_ioctl_sc_emerg_t)
#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x3f, ec_ioctl_sc_emerg_t)
#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x40, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x41, ec_ioctl_reg_request_t)
#define EC_IOCTL_SC_VOE EC_IOWR(0x42, ec_ioctl_voe_t)
#define EC_IOCTL_SC_STATE EC_IOWR(0x43, ec_ioctl_sc_state_t)
#define EC_IOCTL_SC_IDN EC_IOW(0x44, ec_ioctl_sc_idn_t)
#define EC_IOCTL_SC_FLAG EC_IOW(0x45, ec_ioctl_sc_flag_t)
#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x46)
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x47)
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x48)
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x49)
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x4a, ec_ioctl_domain_state_t)
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x4b, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x4c, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x4d, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x4e, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x4f, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x50, ec_ioctl_sdo_request_t)
#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x51, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x52, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x53, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x54, ec_ioctl_reg_request_t)
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x55, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x56, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ EC_IOW(0x57, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x58, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x59, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x5a, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_DATA EC_IOWR(0x5b, ec_ioctl_voe_t)
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x5c, size_t)
#define EC_IOCTL_SC_SOE_REQUEST EC_IOWR(0x41, ec_ioctl_soe_request_t)
#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x42, ec_ioctl_reg_request_t)
#define EC_IOCTL_SC_VOE EC_IOWR(0x43, ec_ioctl_voe_t)
#define EC_IOCTL_SC_STATE EC_IOWR(0x44, ec_ioctl_sc_state_t)
#define EC_IOCTL_SC_IDN EC_IOW(0x45, ec_ioctl_sc_idn_t)
#define EC_IOCTL_SC_FLAG EC_IOW(0x46, ec_ioctl_sc_flag_t)
#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x47)
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x48)
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x49)
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x4a)
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x4b, ec_ioctl_domain_state_t)
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x4c, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x4d, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x4e, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x4f, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x50, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x51, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SOE_REQUEST_IDN EC_IOWR(0x52, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_TIMEOUT EC_IOWR(0x53, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_STATE EC_IOWR(0x54, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_READ EC_IOWR(0x55, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_WRITE EC_IOWR(0x56, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_DATA EC_IOWR(0x57, ec_ioctl_soe_request_t)
#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x58, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x59, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x5a, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x5b, ec_ioctl_reg_request_t)
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x5c, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x5d, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ EC_IOW(0x5e, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x5f, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x60, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x61, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_DATA EC_IOWR(0x62, ec_ioctl_voe_t)
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x63, size_t)
/*****************************************************************************/
@@ -762,6 +769,22 @@ typedef struct {
/*****************************************************************************/
typedef struct {
// inputs
uint32_t config_index;
// inputs/outputs
uint32_t request_index;
uint8_t drive_no;
uint16_t idn;
size_t size;
uint8_t *data;
uint32_t timeout;
ec_request_state_t state;
} ec_ioctl_soe_request_t;
/*****************************************************************************/
typedef struct {
// inputs
uint32_t config_index;
+4 -4
View File
@@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
@@ -61,10 +59,12 @@ void ec_sdo_request_init(
req->data = NULL;
req->mem_size = 0;
req->data_size = 0;
req->dir = EC_DIR_INVALID;
req->issue_timeout = 0; // no timeout
req->response_timeout = EC_SDO_REQUEST_RESPONSE_TIMEOUT;
req->dir = EC_DIR_INVALID;
req->state = EC_INT_REQUEST_INIT;
req->jiffies_start = 0U;
req->jiffies_sent = 0U;
req->errno = 0;
req->abort_code = 0x00000000;
}
+1 -3
View File
@@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
+85 -4
View File
@@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
@@ -87,6 +85,7 @@ void ec_slave_config_init(
INIT_LIST_HEAD(&sc->sdo_configs);
INIT_LIST_HEAD(&sc->sdo_requests);
INIT_LIST_HEAD(&sc->soe_requests);
INIT_LIST_HEAD(&sc->reg_requests);
INIT_LIST_HEAD(&sc->voe_handlers);
INIT_LIST_HEAD(&sc->soe_configs);
@@ -132,6 +131,13 @@ void ec_slave_config_clear(
kfree(req);
}
// free all SoE requests
list_for_each_entry_safe(soe, next_soe, &sc->soe_requests, list) {
list_del(&soe->list);
ec_soe_request_clear(soe);
kfree(soe);
}
// free all register requests
list_for_each_entry_safe(reg, next_reg, &sc->reg_requests, list) {
list_del(&reg->list);
@@ -507,7 +513,7 @@ const ec_flag_t *ec_slave_config_get_flag_by_pos_const(
/*****************************************************************************/
/** Finds a CoE handler via its position in the list.
/** Finds a CoE SDO request via its position in the list.
*
* \return Search result, or NULL.
*/
@@ -529,6 +535,28 @@ ec_sdo_request_t *ec_slave_config_find_sdo_request(
/*****************************************************************************/
/** Finds a SoE request via its position in the list.
*
* \return Search result, or NULL.
*/
ec_soe_request_t *ec_slave_config_find_soe_request(
ec_slave_config_t *sc, /**< Slave configuration. */
unsigned int pos /**< Position in the list. */
)
{
ec_soe_request_t *req;
list_for_each_entry(req, &sc->soe_requests, list) {
if (pos--)
continue;
return req;
}
return NULL;
}
/*****************************************************************************/
/** Finds a register handler via its position in the list.
*
* \return Search result, or NULL.
@@ -1158,6 +1186,58 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request(
/*****************************************************************************/
/** Same as ecrt_slave_config_create_soe_request(), but with ERR_PTR() return
* value.
*/
ec_soe_request_t *ecrt_slave_config_create_soe_request_err(
ec_slave_config_t *sc, uint8_t drive_no, uint16_t idn, size_t size)
{
ec_soe_request_t *req;
int ret;
EC_CONFIG_DBG(sc, 1, "%s(sc = 0x%p, "
"drive_no = 0x%02X, idn = 0x%04X, size = %zu)\n",
__func__, sc, drive_no, idn, size);
if (!(req = (ec_soe_request_t *)
kmalloc(sizeof(ec_soe_request_t), GFP_KERNEL))) {
EC_CONFIG_ERR(sc, "Failed to allocate IDN request memory!\n");
return ERR_PTR(-ENOMEM);
}
ec_soe_request_init(req);
ecrt_soe_request_idn(req, drive_no, idn);
ret = ec_soe_request_alloc(req, size);
if (ret < 0) {
ec_soe_request_clear(req);
kfree(req);
return ERR_PTR(ret);
}
// prepare data for optional writing
memset(req->data, 0x00, size);
req->data_size = size;
down(&sc->master->master_sem);
list_add_tail(&req->list, &sc->soe_requests);
up(&sc->master->master_sem);
return req;
}
/*****************************************************************************/
ec_soe_request_t *ecrt_slave_config_create_soe_request(
ec_slave_config_t *sc, uint8_t drive_no, uint16_t idn, size_t size)
{
ec_soe_request_t *req = ecrt_slave_config_create_soe_request_err(sc,
drive_no, idn, size);
return IS_ERR(req) ? NULL : req;
}
/*****************************************************************************/
/** Same as ecrt_slave_config_create_reg_request(), but with ERR_PTR() return
* value.
*/
@@ -1373,6 +1453,7 @@ EXPORT_SYMBOL(ecrt_slave_config_emerg_pop);
EXPORT_SYMBOL(ecrt_slave_config_emerg_clear);
EXPORT_SYMBOL(ecrt_slave_config_emerg_overruns);
EXPORT_SYMBOL(ecrt_slave_config_create_sdo_request);
EXPORT_SYMBOL(ecrt_slave_config_create_soe_request);
EXPORT_SYMBOL(ecrt_slave_config_create_voe_handler);
EXPORT_SYMBOL(ecrt_slave_config_create_reg_request);
EXPORT_SYMBOL(ecrt_slave_config_state);
+6 -3
View File
@@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
@@ -143,6 +141,7 @@ struct ec_slave_config {
struct list_head sdo_configs; /**< List of SDO configurations. */
struct list_head sdo_requests; /**< List of SDO requests. */
struct list_head soe_requests; /**< List of SoE requests. */
struct list_head voe_handlers; /**< List of VoE handlers. */
struct list_head reg_requests; /**< List of register requests. */
struct list_head soe_configs; /**< List of SoE configurations. */
@@ -173,6 +172,8 @@ const ec_flag_t *ec_slave_config_get_flag_by_pos_const(
const ec_slave_config_t *, unsigned int);
ec_sdo_request_t *ec_slave_config_find_sdo_request(ec_slave_config_t *,
unsigned int);
ec_soe_request_t *ec_slave_config_find_soe_request(ec_slave_config_t *,
unsigned int);
ec_reg_request_t *ec_slave_config_find_reg_request(ec_slave_config_t *,
unsigned int);
ec_voe_handler_t *ec_slave_config_find_voe_handler(ec_slave_config_t *,
@@ -181,6 +182,8 @@ ec_flag_t *ec_slave_config_find_flag(ec_slave_config_t *, const char *);
ec_sdo_request_t *ecrt_slave_config_create_sdo_request_err(
ec_slave_config_t *, uint16_t, uint8_t, size_t);
ec_soe_request_t *ecrt_slave_config_create_soe_request_err(
ec_slave_config_t *, uint8_t, uint16_t, size_t);
ec_voe_handler_t *ecrt_slave_config_create_voe_handler_err(
ec_slave_config_t *, size_t);
ec_reg_request_t *ecrt_slave_config_create_reg_request_err(
+84 -3
View File
@@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
@@ -64,8 +62,10 @@ void ec_soe_request_init(
req->data = NULL;
req->mem_size = 0;
req->data_size = 0;
req->issue_timeout = 0; // no timeout
req->dir = EC_DIR_INVALID;
req->state = EC_INT_REQUEST_INIT;
req->jiffies_start = 0U;
req->jiffies_sent = 0U;
req->error_code = 0x0000;
}
@@ -236,6 +236,7 @@ void ec_soe_request_read(
req->dir = EC_DIR_INPUT;
req->state = EC_INT_REQUEST_QUEUED;
req->error_code = 0x0000;
req->jiffies_start = jiffies;
}
/*****************************************************************************/
@@ -249,6 +250,86 @@ void ec_soe_request_write(
req->dir = EC_DIR_OUTPUT;
req->state = EC_INT_REQUEST_QUEUED;
req->error_code = 0x0000;
req->jiffies_start = jiffies;
}
/*****************************************************************************/
/** Checks, if the timeout was exceeded.
*
* \return non-zero if the timeout was exceeded, else zero.
*/
int ec_soe_request_timed_out(const ec_soe_request_t *req /**< SDO request. */)
{
return req->issue_timeout
&& jiffies - req->jiffies_start > HZ * req->issue_timeout / 1000;
}
/*****************************************************************************
* Application interface.
****************************************************************************/
void ecrt_soe_request_idn(ec_soe_request_t *req, uint8_t drive_no,
uint16_t idn)
{
req->drive_no = drive_no;
req->idn = idn;
}
/*****************************************************************************/
void ecrt_soe_request_timeout(ec_soe_request_t *req, uint32_t timeout)
{
req->issue_timeout = timeout;
}
/*****************************************************************************/
uint8_t *ecrt_soe_request_data(ec_soe_request_t *req)
{
return req->data;
}
/*****************************************************************************/
size_t ecrt_soe_request_data_size(const ec_soe_request_t *req)
{
return req->data_size;
}
/*****************************************************************************/
ec_request_state_t ecrt_soe_request_state(ec_soe_request_t *req)
{
return ec_request_state_translation_table[req->state];
}
/*****************************************************************************/
void ecrt_soe_request_read(ec_soe_request_t *req)
{
ec_soe_request_read(req);
}
/*****************************************************************************/
void ecrt_soe_request_write(ec_soe_request_t *req)
{
ec_soe_request_write(req);
}
/*****************************************************************************/
/** \cond */
EXPORT_SYMBOL(ecrt_soe_request_idn);
EXPORT_SYMBOL(ecrt_soe_request_timeout);
EXPORT_SYMBOL(ecrt_soe_request_data);
EXPORT_SYMBOL(ecrt_soe_request_data_size);
EXPORT_SYMBOL(ecrt_soe_request_state);
EXPORT_SYMBOL(ecrt_soe_request_read);
EXPORT_SYMBOL(ecrt_soe_request_write);
/** \endcond */
/*****************************************************************************/
+6 -2
View File
@@ -45,7 +45,7 @@
/** Sercos-over-EtherCAT request.
*/
typedef struct {
struct ec_soe_request {
struct list_head list; /**< List item. */
uint8_t drive_no; /**< Drive number. */
uint16_t idn; /**< Sercos ID-Number. */
@@ -53,13 +53,16 @@ typedef struct {
uint8_t *data; /**< Pointer to SDO data. */
size_t mem_size; /**< Size of SDO data memory. */
size_t data_size; /**< Size of SDO data. */
uint32_t issue_timeout; /**< Maximum time in ms, the processing of the
request may take. */
ec_direction_t dir; /**< Direction. EC_DIR_OUTPUT means writing to the
slave, EC_DIR_INPUT means reading from the slave. */
ec_internal_request_state_t state; /**< Request state. */
unsigned long jiffies_start; /**< Jiffies, when the request was issued. */
unsigned long jiffies_sent; /**< Jiffies, when the upload/download
request was sent. */
uint16_t error_code; /**< SoE error code. */
} ec_soe_request_t;
};
/*****************************************************************************/
@@ -74,6 +77,7 @@ int ec_soe_request_copy_data(ec_soe_request_t *, const uint8_t *, size_t);
int ec_soe_request_append_data(ec_soe_request_t *, const uint8_t *, size_t);
void ec_soe_request_read(ec_soe_request_t *);
void ec_soe_request_write(ec_soe_request_t *);
int ec_soe_request_timed_out(const ec_soe_request_t *);
/*****************************************************************************/