Added API for querying CoE emergency requests.
This commit is contained in:
parent
15516c1f55
commit
cd415846d5
|
|
@ -48,6 +48,10 @@
|
|||
* redundancy features.
|
||||
* - Added ecrt_sdo_request_index() to change SDO index and subindex after
|
||||
* handler creation.
|
||||
* - Added interface for retrieving CoE emergency messages, i. e.
|
||||
* ecrt_slave_config_emerg_size(), ecrt_slave_config_emerg_pop(),
|
||||
* ecrt_slave_config_emerg_clear(), ecrt_slave_config_emerg_overruns() and
|
||||
* the defines EC_HAVE_EMERGENCY and EC_COE_EMERGENCY_MSG_SIZE.
|
||||
*
|
||||
* Changes in version 1.5:
|
||||
*
|
||||
|
|
@ -140,6 +144,12 @@
|
|||
*/
|
||||
#define EC_HAVE_REDUNDANCY
|
||||
|
||||
/** Defined, if the CoE emergency ring feature is available.
|
||||
*
|
||||
* I. e. if the ecrt_slave_config_emerg_*() methods are available.
|
||||
*/
|
||||
#define EC_HAVE_EMERGENCY
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** End of list marker.
|
||||
|
|
@ -172,6 +182,12 @@
|
|||
#define EC_TIMEVAL2NANO(TV) \
|
||||
(((TV).tv_sec - 946684800ULL) * 1000000000ULL + (TV).tv_usec * 1000ULL)
|
||||
|
||||
/** Size of a CoE emergency message in byte.
|
||||
*
|
||||
* \see ecrt_slave_config_emerg_pop().
|
||||
*/
|
||||
#define EC_COE_EMERGENCY_MSG_SIZE 8
|
||||
|
||||
/******************************************************************************
|
||||
* Data types
|
||||
*****************************************************************************/
|
||||
|
|
@ -1283,6 +1299,55 @@ int ecrt_slave_config_complete_sdo(
|
|||
size_t size /**< Size of the \a data. */
|
||||
);
|
||||
|
||||
/** Set the size of the CoE emergency ring buffer.
|
||||
*
|
||||
* The initial size is zero, so all messages will be dropped. This method can
|
||||
* be called even after master activation, but it will clear the ring buffer!
|
||||
*
|
||||
* \return 0 on success, or negative error code.
|
||||
*/
|
||||
int ecrt_slave_config_emerg_size(
|
||||
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||
size_t elements /**< Number of records of the CoE emergency ring. */
|
||||
);
|
||||
|
||||
/** Read and remove one record from the CoE emergency ring buffer.
|
||||
*
|
||||
* A record consists of 8 bytes:
|
||||
*
|
||||
* Byte 0-1: Error code (little endian)
|
||||
* Byte 2: Error register
|
||||
* Byte 3-7: Data
|
||||
*
|
||||
* \return 0 on success (record popped), or negative error code (i. e.
|
||||
* -ENOENT, if ring is empty).
|
||||
*/
|
||||
int ecrt_slave_config_emerg_pop(
|
||||
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||
uint8_t *target /**< Pointer to target memory (at least
|
||||
EC_COE_EMERGENCY_MSG_SIZE bytes). */
|
||||
);
|
||||
|
||||
/** Clears CoE emergency ring buffer and the overrun counter.
|
||||
*
|
||||
* \return 0 on success, or negative error code.
|
||||
*/
|
||||
int ecrt_slave_config_emerg_clear(
|
||||
ec_slave_config_t *sc /**< Slave configuration. */
|
||||
);
|
||||
|
||||
/** Read the number of CoE emergency overruns.
|
||||
*
|
||||
* The overrun counter will be incremented when a CoE emergency message could
|
||||
* not be stored in the ring buffer and had to be dropped. Call
|
||||
* ecrt_slave_config_emerg_clear() to reset the counter.
|
||||
*
|
||||
* \return Number of overruns since last clear, or negative error code.
|
||||
*/
|
||||
int ecrt_slave_config_emerg_overruns(
|
||||
ec_slave_config_t *sc /**< Slave configuration. */
|
||||
);
|
||||
|
||||
/** Create an SDO request to exchange SDOs during realtime operation.
|
||||
*
|
||||
* The created SDO request object is freed automatically when the master is
|
||||
|
|
|
|||
|
|
@ -403,6 +403,84 @@ int ecrt_slave_config_sdo32(ec_slave_config_t *sc, uint16_t index,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_emerg_size(ec_slave_config_t *sc, size_t elements)
|
||||
{
|
||||
ec_ioctl_sc_emerg_t io;
|
||||
int ret;
|
||||
|
||||
io.config_index = sc->index;
|
||||
io.size = elements;
|
||||
|
||||
ret = ioctl(sc->master->fd, EC_IOCTL_SC_EMERG_SIZE, &io);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to set emergency ring size: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
return -EC_IOCTL_ERRNO(ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_emerg_pop(ec_slave_config_t *sc, uint8_t *target)
|
||||
{
|
||||
ec_ioctl_sc_emerg_t io;
|
||||
int ret;
|
||||
|
||||
io.config_index = sc->index;
|
||||
io.target = target;
|
||||
|
||||
ret = ioctl(sc->master->fd, EC_IOCTL_SC_EMERG_POP, &io);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to get emergency message: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
return -EC_IOCTL_ERRNO(ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_emerg_clear(ec_slave_config_t *sc)
|
||||
{
|
||||
ec_ioctl_sc_emerg_t io;
|
||||
int ret;
|
||||
|
||||
io.config_index = sc->index;
|
||||
|
||||
ret = ioctl(sc->master->fd, EC_IOCTL_SC_EMERG_CLEAR, &io);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to clear emergency ring: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
return -EC_IOCTL_ERRNO(ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_emerg_overruns(ec_slave_config_t *sc)
|
||||
{
|
||||
ec_ioctl_sc_emerg_t io;
|
||||
int ret;
|
||||
|
||||
io.config_index = sc->index;
|
||||
|
||||
ret = ioctl(sc->master->fd, EC_IOCTL_SC_EMERG_OVERRUNS, &io);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to get emergency overruns: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
return -EC_IOCTL_ERRNO(ret);
|
||||
}
|
||||
|
||||
return io.overruns;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_slave_config_add_sdo_request(ec_slave_config_t *sc,
|
||||
ec_sdo_request_t *req)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ obj-m := ec_master.o
|
|||
|
||||
ec_master-objs := \
|
||||
cdev.o \
|
||||
coe_emerg_ring.o \
|
||||
datagram.o \
|
||||
datagram_pair.o \
|
||||
device.o \
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
# using HEADERS to enable tags target
|
||||
noinst_HEADERS = \
|
||||
cdev.c cdev.h \
|
||||
coe_emerg_ring.c coe_emerg_ring.h \
|
||||
datagram.c datagram.h \
|
||||
datagram_pair.c datagram_pair.h \
|
||||
debug.c debug.h \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,170 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
* The IgH EtherCAT Master is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* The IgH EtherCAT Master is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with the IgH EtherCAT Master; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* The license mentioned above concerns the source code only. Using the
|
||||
* EtherCAT technology and brand is only permitted in compliance with the
|
||||
* industrial property and similar rights of Beckhoff Automation GmbH.
|
||||
*
|
||||
* vim: expandtab
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT CoE emergency ring buffer methods.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "coe_emerg_ring.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Emergency ring buffer constructor.
|
||||
*/
|
||||
void ec_coe_emerg_ring_init(
|
||||
ec_coe_emerg_ring_t *ring, /**< Emergency ring. */
|
||||
ec_slave_config_t *sc /**< Slave configuration. */
|
||||
)
|
||||
{
|
||||
ring->sc = sc;
|
||||
ring->msgs = NULL;
|
||||
ring->size = 0;
|
||||
ring->read_index = 0;
|
||||
ring->write_index = 0;
|
||||
ring->overruns = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Emergency ring buffer destructor.
|
||||
*/
|
||||
void ec_coe_emerg_ring_clear(
|
||||
ec_coe_emerg_ring_t *ring /**< Emergency ring. */
|
||||
)
|
||||
{
|
||||
if (ring->msgs) {
|
||||
kfree(ring->msgs);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Set the ring size.
|
||||
*/
|
||||
int ec_coe_emerg_ring_size(
|
||||
ec_coe_emerg_ring_t *ring, /**< Emergency ring. */
|
||||
size_t size /**< Maximum number of messages in the ring. */
|
||||
)
|
||||
{
|
||||
ring->size = 0;
|
||||
|
||||
if (size < 0) {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
ring->read_index = ring->write_index = 0;
|
||||
|
||||
if (ring->msgs) {
|
||||
kfree(ring->msgs);
|
||||
}
|
||||
ring->msgs = NULL;
|
||||
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ring->msgs = kmalloc(sizeof(ec_coe_emerg_msg_t) * (size + 1), GFP_KERNEL);
|
||||
if (!ring->msgs) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ring->size = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Add a new emergency message.
|
||||
*/
|
||||
void ec_coe_emerg_ring_push(
|
||||
ec_coe_emerg_ring_t *ring, /**< Emergency ring. */
|
||||
const u8 *msg /**< Emergency message. */
|
||||
)
|
||||
{
|
||||
if (!ring->size ||
|
||||
(ring->write_index + 1) % (ring->size + 1) == ring->read_index) {
|
||||
ring->overruns++;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(ring->msgs[ring->write_index].data, msg,
|
||||
EC_COE_EMERGENCY_MSG_SIZE);
|
||||
ring->write_index = (ring->write_index + 1) % (ring->size + 1);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Remove an emergency message from the ring.
|
||||
*/
|
||||
int ec_coe_emerg_ring_pop(
|
||||
ec_coe_emerg_ring_t *ring, /**< Emergency ring. */
|
||||
u8 *msg /**< Memory to store the emergency message. */
|
||||
)
|
||||
{
|
||||
if (ring->read_index == ring->write_index) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
memcpy(msg, ring->msgs[ring->read_index].data, EC_COE_EMERGENCY_MSG_SIZE);
|
||||
ring->read_index = (ring->read_index + 1) % (ring->size + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Clear the ring.
|
||||
*/
|
||||
int ec_coe_emerg_ring_clear_ring(
|
||||
ec_coe_emerg_ring_t *ring /**< Emergency ring. */
|
||||
)
|
||||
{
|
||||
ring->read_index = ring->write_index;
|
||||
ring->overruns = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Read the number of overruns.
|
||||
*/
|
||||
int ec_coe_emerg_ring_overruns(
|
||||
ec_coe_emerg_ring_t *ring /**< Emergency ring. */
|
||||
)
|
||||
{
|
||||
return ring->overruns;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
* The IgH EtherCAT Master is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* The IgH EtherCAT Master is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with the IgH EtherCAT Master; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* The license mentioned above concerns the source code only. Using the
|
||||
* EtherCAT technology and brand is only permitted in compliance with the
|
||||
* industrial property and similar rights of Beckhoff Automation GmbH.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT CoE emergency ring buffer structure.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __EC_COE_EMERG_RING_H__
|
||||
#define __EC_COE_EMERG_RING_H__
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** EtherCAT CoE emergency message record.
|
||||
*/
|
||||
typedef struct {
|
||||
u8 data[EC_COE_EMERGENCY_MSG_SIZE];
|
||||
} ec_coe_emerg_msg_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** EtherCAT CoE emergency ring buffer.
|
||||
*/
|
||||
typedef struct {
|
||||
ec_slave_config_t *sc; /**< Slave configuration owning the ring. */
|
||||
|
||||
ec_coe_emerg_msg_t *msgs;
|
||||
size_t size;
|
||||
|
||||
unsigned int read_index;
|
||||
unsigned int write_index;
|
||||
unsigned int overruns;
|
||||
} ec_coe_emerg_ring_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_coe_emerg_ring_init(ec_coe_emerg_ring_t *, ec_slave_config_t *);
|
||||
void ec_coe_emerg_ring_clear(ec_coe_emerg_ring_t *);
|
||||
|
||||
int ec_coe_emerg_ring_size(ec_coe_emerg_ring_t *, size_t);
|
||||
void ec_coe_emerg_ring_push(ec_coe_emerg_ring_t *, const u8 *);
|
||||
int ec_coe_emerg_ring_pop(ec_coe_emerg_ring_t *, u8 *);
|
||||
int ec_coe_emerg_ring_clear_ring(ec_coe_emerg_ring_t *);
|
||||
int ec_coe_emerg_ring_overruns(ec_coe_emerg_ring_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif
|
||||
|
|
@ -38,6 +38,7 @@
|
|||
#include "master.h"
|
||||
#include "mailbox.h"
|
||||
#include "fsm_coe.h"
|
||||
#include "slave_config.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -269,6 +270,13 @@ int ec_fsm_coe_check_emergency(
|
|||
return 1;
|
||||
}
|
||||
|
||||
{
|
||||
ec_slave_config_t *sc = fsm->slave->config;
|
||||
if (sc) {
|
||||
ec_coe_emerg_ring_push(&sc->emerg_ring, data + 2);
|
||||
}
|
||||
}
|
||||
|
||||
EC_SLAVE_WARN(fsm->slave, "CoE Emergency Request received:\n"
|
||||
"Error code 0x%04X, Error register 0x%02X, data:\n",
|
||||
EC_READ_U16(data + 2), EC_READ_U8(data + 4));
|
||||
|
|
|
|||
191
master/ioctl.c
191
master/ioctl.c
|
|
@ -2276,6 +2276,169 @@ static int ec_ioctl_sc_sdo(
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Set the emergency ring buffer size.
|
||||
*/
|
||||
static int ec_ioctl_sc_emerg_size(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
void *arg, /**< ioctl() argument. */
|
||||
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
ec_ioctl_sc_emerg_t io;
|
||||
ec_slave_config_t *sc;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!ctx->requested))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&io, (void __user *) arg, sizeof(io)))
|
||||
return -EFAULT;
|
||||
|
||||
if (down_interruptible(&master->master_sem)) {
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if (!(sc = ec_master_get_config(master, io.config_index))) {
|
||||
up(&master->master_sem);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = ecrt_slave_config_emerg_size(sc, io.size);
|
||||
|
||||
up(&master->master_sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Get an emergency message from the ring.
|
||||
*/
|
||||
static int ec_ioctl_sc_emerg_pop(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
void *arg, /**< ioctl() argument. */
|
||||
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
ec_ioctl_sc_emerg_t io;
|
||||
ec_slave_config_t *sc;
|
||||
u8 msg[EC_COE_EMERGENCY_MSG_SIZE];
|
||||
int ret;
|
||||
|
||||
if (unlikely(!ctx->requested))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&io, (void __user *) arg, sizeof(io)))
|
||||
return -EFAULT;
|
||||
|
||||
if (down_interruptible(&master->master_sem)) {
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if (!(sc = ec_master_get_config(master, io.config_index))) {
|
||||
up(&master->master_sem);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = ecrt_slave_config_emerg_pop(sc, msg);
|
||||
|
||||
up(&master->master_sem);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (copy_to_user((void __user *) io.target, msg, sizeof(msg))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Clear the emergency ring.
|
||||
*/
|
||||
static int ec_ioctl_sc_emerg_clear(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
void *arg, /**< ioctl() argument. */
|
||||
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
ec_ioctl_sc_emerg_t io;
|
||||
ec_slave_config_t *sc;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!ctx->requested))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&io, (void __user *) arg, sizeof(io)))
|
||||
return -EFAULT;
|
||||
|
||||
if (down_interruptible(&master->master_sem)) {
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if (!(sc = ec_master_get_config(master, io.config_index))) {
|
||||
up(&master->master_sem);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = ecrt_slave_config_emerg_clear(sc);
|
||||
|
||||
up(&master->master_sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Get the number of emergency overruns.
|
||||
*/
|
||||
static int ec_ioctl_sc_emerg_overruns(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
void *arg, /**< ioctl() argument. */
|
||||
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
ec_ioctl_sc_emerg_t io;
|
||||
ec_slave_config_t *sc;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!ctx->requested))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&io, (void __user *) arg, sizeof(io)))
|
||||
return -EFAULT;
|
||||
|
||||
if (down_interruptible(&master->master_sem)) {
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if (!(sc = ec_master_get_config(master, io.config_index))) {
|
||||
up(&master->master_sem);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = ecrt_slave_config_emerg_overruns(sc);
|
||||
|
||||
up(&master->master_sem);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
io.overruns = ret;
|
||||
|
||||
if (copy_to_user((void __user *) arg, &io, sizeof(io))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Create an SDO request.
|
||||
*/
|
||||
static int ec_ioctl_sc_create_sdo_request(
|
||||
|
|
@ -3678,6 +3841,34 @@ long EC_IOCTL(ec_master_t *master, ec_ioctl_context_t *ctx,
|
|||
}
|
||||
ret = ec_ioctl_sc_sdo(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SC_EMERG_SIZE:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
ret = ec_ioctl_sc_emerg_size(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SC_EMERG_POP:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
ret = ec_ioctl_sc_emerg_pop(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SC_EMERG_CLEAR:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
ret = ec_ioctl_sc_emerg_clear(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SC_EMERG_OVERRUNS:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
ret = ec_ioctl_sc_emerg_overruns(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SC_SDO_REQUEST:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
*
|
||||
* Increment this when changing the ioctl interface!
|
||||
*/
|
||||
#define EC_IOCTL_VERSION_MAGIC 20
|
||||
#define EC_IOCTL_VERSION_MAGIC 21
|
||||
|
||||
// Command-line tool
|
||||
#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)
|
||||
|
|
@ -117,28 +117,32 @@
|
|||
#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x33, ec_ioctl_reg_pdo_entry_t)
|
||||
#define EC_IOCTL_SC_DC EC_IOW(0x34, ec_ioctl_config_t)
|
||||
#define EC_IOCTL_SC_SDO EC_IOW(0x35, ec_ioctl_sc_sdo_t)
|
||||
#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x36, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SC_VOE EC_IOWR(0x37, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SC_STATE EC_IOWR(0x38, ec_ioctl_sc_state_t)
|
||||
#define EC_IOCTL_SC_IDN EC_IOW(0x39, ec_ioctl_sc_idn_t)
|
||||
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x3a)
|
||||
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x3b)
|
||||
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x3c)
|
||||
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x3d, ec_ioctl_domain_state_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x3e, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x3f, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x40, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x41, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x42, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x43, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x44, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x45, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ EC_IOW(0x46, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x47, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x48, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x49, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_DATA EC_IOWR(0x4a, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x4b, size_t)
|
||||
#define EC_IOCTL_SC_EMERG_SIZE EC_IOW(0x36, ec_ioctl_sc_emerg_t)
|
||||
#define EC_IOCTL_SC_EMERG_POP EC_IOWR(0x37, ec_ioctl_sc_emerg_t)
|
||||
#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x38, ec_ioctl_sc_emerg_t)
|
||||
#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x39, ec_ioctl_sc_emerg_t)
|
||||
#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x3a, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SC_VOE EC_IOWR(0x3b, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SC_STATE EC_IOWR(0x3c, ec_ioctl_sc_state_t)
|
||||
#define EC_IOCTL_SC_IDN EC_IOW(0x3d, ec_ioctl_sc_idn_t)
|
||||
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x3e)
|
||||
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x3f)
|
||||
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x40)
|
||||
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x41, ec_ioctl_domain_state_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x42, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x43, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x44, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x45, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x46, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x47, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x48, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x49, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ EC_IOW(0x4a, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x4b, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x4c, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x4d, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_DATA EC_IOWR(0x4e, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x4f, size_t)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -619,6 +623,18 @@ typedef struct {
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
// inputs
|
||||
uint32_t config_index;
|
||||
size_t size;
|
||||
uint8_t *target;
|
||||
|
||||
// outputs
|
||||
int32_t overruns;
|
||||
} ec_ioctl_sc_emerg_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
// inputs
|
||||
uint32_t config_index;
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ void ec_slave_config_init(
|
|||
INIT_LIST_HEAD(&sc->sdo_requests);
|
||||
INIT_LIST_HEAD(&sc->voe_handlers);
|
||||
INIT_LIST_HEAD(&sc->soe_configs);
|
||||
|
||||
ec_coe_emerg_ring_init(&sc->emerg_ring, sc);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -138,6 +140,8 @@ void ec_slave_config_clear(
|
|||
ec_soe_request_clear(soe);
|
||||
kfree(soe);
|
||||
}
|
||||
|
||||
ec_coe_emerg_ring_clear(&sc->emerg_ring);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -881,6 +885,34 @@ int ecrt_slave_config_complete_sdo(ec_slave_config_t *sc, uint16_t index,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_emerg_size(ec_slave_config_t *sc, size_t elements)
|
||||
{
|
||||
return ec_coe_emerg_ring_size(&sc->emerg_ring, elements);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_emerg_pop(ec_slave_config_t *sc, uint8_t *target)
|
||||
{
|
||||
return ec_coe_emerg_ring_pop(&sc->emerg_ring, target);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_emerg_clear(ec_slave_config_t *sc)
|
||||
{
|
||||
return ec_coe_emerg_ring_clear_ring(&sc->emerg_ring);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_emerg_overruns(ec_slave_config_t *sc)
|
||||
{
|
||||
return ec_coe_emerg_ring_overruns(&sc->emerg_ring);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Same as ecrt_slave_config_create_sdo_request(), but with ERR_PTR() return
|
||||
* value.
|
||||
*/
|
||||
|
|
@ -1063,6 +1095,10 @@ EXPORT_SYMBOL(ecrt_slave_config_sdo8);
|
|||
EXPORT_SYMBOL(ecrt_slave_config_sdo16);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_sdo32);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_complete_sdo);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_emerg_size);
|
||||
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_voe_handler);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_state);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#include "slave.h"
|
||||
#include "sync_config.h"
|
||||
#include "fmmu_config.h"
|
||||
#include "coe_emerg_ring.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -141,6 +142,8 @@ struct ec_slave_config {
|
|||
struct list_head sdo_requests; /**< List of SDO requests. */
|
||||
struct list_head voe_handlers; /**< List of VoE handlers. */
|
||||
struct list_head soe_configs; /**< List of SoE configurations. */
|
||||
|
||||
ec_coe_emerg_ring_t emerg_ring; /**< CoE emergency ring buffer. */
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
Loading…
Reference in New Issue