fp@2433: /****************************************************************************** fp@2433: * fp@2433: * $Id$ fp@2433: * fp@2433: * Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH fp@2433: * fp@2433: * This file is part of the IgH EtherCAT Master. fp@2433: * fp@2433: * The IgH EtherCAT Master is free software; you can redistribute it and/or fp@2433: * modify it under the terms of the GNU General Public License version 2, as fp@2433: * published by the Free Software Foundation. fp@2433: * fp@2433: * The IgH EtherCAT Master is distributed in the hope that it will be useful, fp@2433: * but WITHOUT ANY WARRANTY; without even the implied warranty of fp@2433: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General fp@2433: * Public License for more details. fp@2433: * fp@2433: * You should have received a copy of the GNU General Public License along fp@2433: * with the IgH EtherCAT Master; if not, write to the Free Software fp@2433: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@2433: * fp@2433: * --- fp@2433: * fp@2433: * The license mentioned above concerns the source code only. Using the fp@2433: * EtherCAT technology and brand is only permitted in compliance with the fp@2433: * industrial property and similar rights of Beckhoff Automation GmbH. fp@2433: * fp@2433: *****************************************************************************/ fp@2433: fp@2433: /** fp@2433: \file fp@2433: EtherCAT master character device. fp@2433: */ fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: #include fp@2433: fp@2433: #include "master.h" fp@2433: #include "slave_config.h" fp@2433: #include "voe_handler.h" fp@2433: #include "ethernet.h" fp@2433: #include "ioctl.h" fp@2433: fp@2433: /** Set to 1 to enable ioctl() latency tracing. fp@2433: * fp@2433: * Requires CPU timestamp counter! fp@2433: */ fp@2433: #define DEBUG_LATENCY 0 fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Copies a string to an ioctl structure. fp@2433: */ fp@2433: static void ec_ioctl_strcpy( fp@2433: char *target, /**< Target. */ fp@2433: const char *source /**< Source. */ fp@2433: ) fp@2433: { fp@2433: if (source) { fp@2433: strncpy(target, source, EC_IOCTL_STRING_SIZE); fp@2433: target[EC_IOCTL_STRING_SIZE - 1] = 0; fp@2433: } else { fp@2433: target[0] = 0; fp@2433: } fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get module information. fp@2433: */ fp@2433: static int ec_ioctl_module( fp@2433: void *arg /**< Userspace address to store the results. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_module_t data; fp@2433: fp@2433: data.ioctl_version_magic = EC_IOCTL_VERSION_MAGIC; fp@2433: data.master_count = ec_master_count(); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get master information. fp@2433: */ fp@2433: static int ec_ioctl_master( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< Userspace address to store the results. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_master_t data; fp@2433: unsigned int i, j; fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: data.slave_count = master->slave_count; fp@2433: data.config_count = ec_master_config_count(master); fp@2433: data.domain_count = ec_master_domain_count(master); fp@2433: #ifdef EC_EOE fp@2433: data.eoe_handler_count = ec_master_eoe_handler_count(master); fp@2433: #endif fp@2433: data.phase = (uint8_t) master->phase; fp@2433: data.active = (uint8_t) master->active; fp@2433: data.scan_busy = master->scan_busy; fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (down_interruptible(&master->device_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: for (i = 0; i < EC_NUM_DEVICES; i++) { fp@2433: ec_device_t *device = &master->devices[i]; fp@2433: fp@2433: if (device->dev) { fp@2433: memcpy(data.devices[i].address, fp@2433: device->dev->dev_addr, ETH_ALEN); fp@2433: } else { fp@2433: memcpy(data.devices[i].address, master->macs[i], ETH_ALEN); fp@2433: } fp@2433: data.devices[i].attached = device->dev ? 1 : 0; fp@2433: data.devices[i].link_state = device->link_state ? 1 : 0; fp@2433: data.devices[i].tx_count = device->tx_count; fp@2433: data.devices[i].rx_count = device->rx_count; fp@2433: data.devices[i].tx_bytes = device->tx_bytes; fp@2433: data.devices[i].rx_bytes = device->rx_bytes; fp@2433: data.devices[i].tx_errors = device->tx_errors; fp@2433: for (j = 0; j < EC_RATE_COUNT; j++) { fp@2433: data.devices[i].tx_frame_rates[j] = fp@2433: device->tx_frame_rates[j]; fp@2433: data.devices[i].rx_frame_rates[j] = fp@2433: device->rx_frame_rates[j]; fp@2433: data.devices[i].tx_byte_rates[j] = fp@2433: device->tx_byte_rates[j]; fp@2433: data.devices[i].rx_byte_rates[j] = fp@2433: device->rx_byte_rates[j]; fp@2433: } fp@2433: } fp@2433: fp@2433: data.tx_count = master->device_stats.tx_count; fp@2433: data.rx_count = master->device_stats.rx_count; fp@2433: data.tx_bytes = master->device_stats.tx_bytes; fp@2433: data.rx_bytes = master->device_stats.rx_bytes; fp@2433: for (i = 0; i < EC_RATE_COUNT; i++) { fp@2433: data.tx_frame_rates[i] = fp@2433: master->device_stats.tx_frame_rates[i]; fp@2433: data.rx_frame_rates[i] = fp@2433: master->device_stats.rx_frame_rates[i]; fp@2433: data.tx_byte_rates[i] = fp@2433: master->device_stats.tx_byte_rates[i]; fp@2433: data.rx_byte_rates[i] = fp@2433: master->device_stats.rx_byte_rates[i]; fp@2433: data.loss_rates[i] = fp@2433: master->device_stats.loss_rates[i]; fp@2433: } fp@2433: fp@2433: up(&master->device_sem); fp@2433: fp@2433: data.app_time = master->app_time; fp@2433: data.ref_clock = fp@2433: master->dc_ref_clock ? master->dc_ref_clock->ring_position : 0xffff; fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get slave information. fp@2433: */ fp@2433: static int ec_ioctl_slave( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< Userspace address to store the results. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_t data; fp@2433: const ec_slave_t *slave; fp@2433: int i; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(slave = ec_master_find_slave_const( fp@2433: master, 0, data.position))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.position); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: data.device_index = slave->device_index; fp@2433: data.vendor_id = slave->sii.vendor_id; fp@2433: data.product_code = slave->sii.product_code; fp@2433: data.revision_number = slave->sii.revision_number; fp@2433: data.serial_number = slave->sii.serial_number; fp@2433: data.alias = slave->effective_alias; fp@2433: data.boot_rx_mailbox_offset = slave->sii.boot_rx_mailbox_offset; fp@2433: data.boot_rx_mailbox_size = slave->sii.boot_rx_mailbox_size; fp@2433: data.boot_tx_mailbox_offset = slave->sii.boot_tx_mailbox_offset; fp@2433: data.boot_tx_mailbox_size = slave->sii.boot_tx_mailbox_size; fp@2433: data.std_rx_mailbox_offset = slave->sii.std_rx_mailbox_offset; fp@2433: data.std_rx_mailbox_size = slave->sii.std_rx_mailbox_size; fp@2433: data.std_tx_mailbox_offset = slave->sii.std_tx_mailbox_offset; fp@2433: data.std_tx_mailbox_size = slave->sii.std_tx_mailbox_size; fp@2433: data.mailbox_protocols = slave->sii.mailbox_protocols; fp@2433: data.has_general_category = slave->sii.has_general; fp@2433: data.coe_details = slave->sii.coe_details; fp@2433: data.general_flags = slave->sii.general_flags; fp@2433: data.current_on_ebus = slave->sii.current_on_ebus; fp@2433: for (i = 0; i < EC_MAX_PORTS; i++) { fp@2433: data.ports[i].desc = slave->ports[i].desc; fp@2433: data.ports[i].link.link_up = slave->ports[i].link.link_up; fp@2433: data.ports[i].link.loop_closed = slave->ports[i].link.loop_closed; fp@2433: data.ports[i].link.signal_detected = fp@2433: slave->ports[i].link.signal_detected; fp@2433: data.ports[i].receive_time = slave->ports[i].receive_time; fp@2433: if (slave->ports[i].next_slave) { fp@2433: data.ports[i].next_slave = fp@2433: slave->ports[i].next_slave->ring_position; fp@2433: } else { fp@2433: data.ports[i].next_slave = 0xffff; fp@2433: } fp@2433: data.ports[i].delay_to_next_dc = slave->ports[i].delay_to_next_dc; fp@2433: } fp@2433: data.fmmu_bit = slave->base_fmmu_bit_operation; fp@2433: data.dc_supported = slave->base_dc_supported; fp@2433: data.dc_range = slave->base_dc_range; fp@2433: data.has_dc_system_time = slave->has_dc_system_time; fp@2433: data.transmission_delay = slave->transmission_delay; fp@2433: data.al_state = slave->current_state; fp@2433: data.error_flag = slave->error_flag; fp@2433: fp@2433: data.sync_count = slave->sii.sync_count; fp@2433: data.sdo_count = ec_slave_sdo_count(slave); fp@2433: data.sii_nwords = slave->sii_nwords; fp@2433: ec_ioctl_strcpy(data.group, slave->sii.group); fp@2433: ec_ioctl_strcpy(data.image, slave->sii.image); fp@2433: ec_ioctl_strcpy(data.order, slave->sii.order); fp@2433: ec_ioctl_strcpy(data.name, slave->sii.name); fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get slave sync manager information. fp@2433: */ fp@2433: static int ec_ioctl_slave_sync( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< Userspace address to store the results. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_sync_t data; fp@2433: const ec_slave_t *slave; fp@2433: const ec_sync_t *sync; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(slave = ec_master_find_slave_const( fp@2433: master, 0, data.slave_position))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave %u does not exist!\n", fp@2433: data.slave_position); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (data.sync_index >= slave->sii.sync_count) { fp@2433: up(&master->master_sem); fp@2433: EC_SLAVE_ERR(slave, "Sync manager %u does not exist!\n", fp@2433: data.sync_index); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: sync = &slave->sii.syncs[data.sync_index]; fp@2433: fp@2433: data.physical_start_address = sync->physical_start_address; fp@2433: data.default_size = sync->default_length; fp@2433: data.control_register = sync->control_register; fp@2433: data.enable = sync->enable; fp@2433: data.pdo_count = ec_pdo_list_count(&sync->pdos); fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get slave sync manager PDO information. fp@2433: */ fp@2433: static int ec_ioctl_slave_sync_pdo( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< Userspace address to store the results. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_sync_pdo_t data; fp@2433: const ec_slave_t *slave; fp@2433: const ec_sync_t *sync; fp@2433: const ec_pdo_t *pdo; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(slave = ec_master_find_slave_const( fp@2433: master, 0, data.slave_position))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave %u does not exist!\n", fp@2433: data.slave_position); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (data.sync_index >= slave->sii.sync_count) { fp@2433: up(&master->master_sem); fp@2433: EC_SLAVE_ERR(slave, "Sync manager %u does not exist!\n", fp@2433: data.sync_index); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: sync = &slave->sii.syncs[data.sync_index]; fp@2433: if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( fp@2433: &sync->pdos, data.pdo_pos))) { fp@2433: up(&master->master_sem); fp@2433: EC_SLAVE_ERR(slave, "Sync manager %u does not contain a PDO with " fp@2433: "position %u!\n", data.sync_index, data.pdo_pos); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: data.index = pdo->index; fp@2433: data.entry_count = ec_pdo_entry_count(pdo); fp@2433: ec_ioctl_strcpy(data.name, pdo->name); fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get slave sync manager PDO entry information. fp@2433: */ fp@2433: static int ec_ioctl_slave_sync_pdo_entry( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< Userspace address to store the results. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_sync_pdo_entry_t data; fp@2433: const ec_slave_t *slave; fp@2433: const ec_sync_t *sync; fp@2433: const ec_pdo_t *pdo; fp@2433: const ec_pdo_entry_t *entry; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(slave = ec_master_find_slave_const( fp@2433: master, 0, data.slave_position))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave %u does not exist!\n", fp@2433: data.slave_position); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (data.sync_index >= slave->sii.sync_count) { fp@2433: up(&master->master_sem); fp@2433: EC_SLAVE_ERR(slave, "Sync manager %u does not exist!\n", fp@2433: data.sync_index); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: sync = &slave->sii.syncs[data.sync_index]; fp@2433: if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( fp@2433: &sync->pdos, data.pdo_pos))) { fp@2433: up(&master->master_sem); fp@2433: EC_SLAVE_ERR(slave, "Sync manager %u does not contain a PDO with " fp@2433: "position %u!\n", data.sync_index, data.pdo_pos); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (!(entry = ec_pdo_find_entry_by_pos_const( fp@2433: pdo, data.entry_pos))) { fp@2433: up(&master->master_sem); fp@2433: EC_SLAVE_ERR(slave, "PDO 0x%04X does not contain an entry with " fp@2433: "position %u!\n", data.pdo_pos, data.entry_pos); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: data.index = entry->index; fp@2433: data.subindex = entry->subindex; fp@2433: data.bit_length = entry->bit_length; fp@2433: ec_ioctl_strcpy(data.name, entry->name); fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get domain information. fp@2433: */ fp@2433: static int ec_ioctl_domain( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< Userspace address to store the results. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_domain_t data; fp@2433: const ec_domain_t *domain; fp@2433: unsigned int dev_idx; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(domain = ec_master_find_domain_const(master, data.index))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Domain %u does not exist!\n", data.index); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: data.data_size = domain->data_size; fp@2433: data.logical_base_address = domain->logical_base_address; fp@2433: for (dev_idx = 0; dev_idx < EC_NUM_DEVICES; dev_idx++) { fp@2433: data.working_counter[dev_idx] = domain->working_counter[dev_idx]; fp@2433: } fp@2433: data.expected_working_counter = domain->expected_working_counter; fp@2433: data.fmmu_count = ec_domain_fmmu_count(domain); fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get domain FMMU information. fp@2433: */ fp@2433: static int ec_ioctl_domain_fmmu( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< Userspace address to store the results. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_domain_fmmu_t data; fp@2433: const ec_domain_t *domain; fp@2433: const ec_fmmu_config_t *fmmu; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(domain = ec_master_find_domain_const(master, data.domain_index))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Domain %u does not exist!\n", fp@2433: data.domain_index); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (!(fmmu = ec_domain_find_fmmu(domain, data.fmmu_index))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Domain %u has less than %u" fp@2433: " fmmu configurations.\n", fp@2433: data.domain_index, data.fmmu_index + 1); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: data.slave_config_alias = fmmu->sc->alias; fp@2433: data.slave_config_position = fmmu->sc->position; fp@2433: data.sync_index = fmmu->sync_index; fp@2433: data.dir = fmmu->dir; fp@2433: data.logical_address = fmmu->logical_start_address; fp@2433: data.data_size = fmmu->data_size; fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get domain data. fp@2433: */ fp@2433: static int ec_ioctl_domain_data( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< Userspace address to store the results. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_domain_data_t data; fp@2433: const ec_domain_t *domain; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(domain = ec_master_find_domain_const(master, data.domain_index))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Domain %u does not exist!\n", fp@2433: data.domain_index); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (domain->data_size != data.data_size) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Data size mismatch %u/%zu!\n", fp@2433: data.data_size, domain->data_size); fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (copy_to_user((void __user *) data.target, domain->data, fp@2433: domain->data_size)) { fp@2433: up(&master->master_sem); fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: up(&master->master_sem); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Set master debug level. fp@2433: */ fp@2433: static int ec_ioctl_master_debug( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: return ec_master_debug_level(master, (unsigned int) arg); fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Issue a bus scan. fp@2433: */ fp@2433: static int ec_ioctl_master_rescan( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: master->fsm.rescan_required = 1; fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Set slave state. fp@2433: */ fp@2433: static int ec_ioctl_slave_state( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_state_t data; fp@2433: ec_slave_t *slave; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(slave = ec_master_find_slave( fp@2433: master, 0, data.slave_position))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave %u does not exist!\n", fp@2433: data.slave_position); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: ec_slave_request_state(slave, data.al_state); fp@2433: fp@2433: up(&master->master_sem); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get slave SDO information. fp@2433: */ fp@2433: static int ec_ioctl_slave_sdo( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_sdo_t data; fp@2433: const ec_slave_t *slave; fp@2433: const ec_sdo_t *sdo; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(slave = ec_master_find_slave_const( fp@2433: master, 0, data.slave_position))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave %u does not exist!\n", fp@2433: data.slave_position); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (!(sdo = ec_slave_get_sdo_by_pos_const( fp@2433: slave, data.sdo_position))) { fp@2433: up(&master->master_sem); fp@2433: EC_SLAVE_ERR(slave, "SDO %u does not exist!\n", data.sdo_position); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: data.sdo_index = sdo->index; fp@2433: data.max_subindex = sdo->max_subindex; fp@2433: ec_ioctl_strcpy(data.name, sdo->name); fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get slave SDO entry information. fp@2433: */ fp@2433: static int ec_ioctl_slave_sdo_entry( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_sdo_entry_t data; fp@2433: const ec_slave_t *slave; fp@2433: const ec_sdo_t *sdo; fp@2433: const ec_sdo_entry_t *entry; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(slave = ec_master_find_slave_const( fp@2433: master, 0, data.slave_position))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave %u does not exist!\n", fp@2433: data.slave_position); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (data.sdo_spec <= 0) { fp@2433: if (!(sdo = ec_slave_get_sdo_by_pos_const( fp@2433: slave, -data.sdo_spec))) { fp@2433: up(&master->master_sem); fp@2433: EC_SLAVE_ERR(slave, "SDO %u does not exist!\n", -data.sdo_spec); fp@2433: return -EINVAL; fp@2433: } fp@2433: } else { fp@2433: if (!(sdo = ec_slave_get_sdo_const( fp@2433: slave, data.sdo_spec))) { fp@2433: up(&master->master_sem); fp@2433: EC_SLAVE_ERR(slave, "SDO 0x%04X does not exist!\n", fp@2433: data.sdo_spec); fp@2433: return -EINVAL; fp@2433: } fp@2433: } fp@2433: fp@2433: if (!(entry = ec_sdo_get_entry_const( fp@2433: sdo, data.sdo_entry_subindex))) { fp@2433: up(&master->master_sem); fp@2433: EC_SLAVE_ERR(slave, "SDO entry 0x%04X:%02X does not exist!\n", fp@2433: sdo->index, data.sdo_entry_subindex); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: data.data_type = entry->data_type; fp@2433: data.bit_length = entry->bit_length; fp@2433: data.read_access[EC_SDO_ENTRY_ACCESS_PREOP] = fp@2433: entry->read_access[EC_SDO_ENTRY_ACCESS_PREOP]; fp@2433: data.read_access[EC_SDO_ENTRY_ACCESS_SAFEOP] = fp@2433: entry->read_access[EC_SDO_ENTRY_ACCESS_SAFEOP]; fp@2433: data.read_access[EC_SDO_ENTRY_ACCESS_OP] = fp@2433: entry->read_access[EC_SDO_ENTRY_ACCESS_OP]; fp@2433: data.write_access[EC_SDO_ENTRY_ACCESS_PREOP] = fp@2433: entry->write_access[EC_SDO_ENTRY_ACCESS_PREOP]; fp@2433: data.write_access[EC_SDO_ENTRY_ACCESS_SAFEOP] = fp@2433: entry->write_access[EC_SDO_ENTRY_ACCESS_SAFEOP]; fp@2433: data.write_access[EC_SDO_ENTRY_ACCESS_OP] = fp@2433: entry->write_access[EC_SDO_ENTRY_ACCESS_OP]; fp@2433: ec_ioctl_strcpy(data.description, entry->description); fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Upload SDO. fp@2433: */ fp@2433: static int ec_ioctl_slave_sdo_upload( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_sdo_upload_t data; fp@2433: uint8_t *target; fp@2433: int ret; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (!(target = kmalloc(data.target_size, GFP_KERNEL))) { fp@2433: EC_MASTER_ERR(master, "Failed to allocate %u bytes" fp@2433: " for SDO upload.\n", data.target_size); fp@2433: return -ENOMEM; fp@2433: } fp@2433: fp@2433: ret = ecrt_master_sdo_upload(master, data.slave_position, fp@2433: data.sdo_index, data.sdo_entry_subindex, target, fp@2433: data.target_size, &data.data_size, &data.abort_code); fp@2433: fp@2433: if (!ret) { fp@2433: if (copy_to_user((void __user *) data.target, fp@2433: target, data.data_size)) { fp@2433: kfree(target); fp@2433: return -EFAULT; fp@2433: } fp@2433: } fp@2433: fp@2433: kfree(target); fp@2433: fp@2433: if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Download SDO. fp@2433: */ fp@2433: static int ec_ioctl_slave_sdo_download( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_sdo_download_t data; fp@2433: uint8_t *sdo_data; fp@2433: int retval; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (!(sdo_data = kmalloc(data.data_size, GFP_KERNEL))) { fp@2433: EC_MASTER_ERR(master, "Failed to allocate %u bytes" fp@2433: " for SDO download.\n", data.data_size); fp@2433: return -ENOMEM; fp@2433: } fp@2433: fp@2433: if (copy_from_user(sdo_data, (void __user *) data.data, data.data_size)) { fp@2433: kfree(sdo_data); fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (data.complete_access) { fp@2433: retval = ecrt_master_sdo_download_complete(master, data.slave_position, fp@2433: data.sdo_index, sdo_data, data.data_size, &data.abort_code); fp@2433: } else { fp@2433: retval = ecrt_master_sdo_download(master, data.slave_position, fp@2433: data.sdo_index, data.sdo_entry_subindex, sdo_data, fp@2433: data.data_size, &data.abort_code); fp@2433: } fp@2433: fp@2433: kfree(sdo_data); fp@2433: fp@2433: if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { fp@2433: retval = -EFAULT; fp@2433: } fp@2433: fp@2433: return retval; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Read a slave's SII. fp@2433: */ fp@2433: static int ec_ioctl_slave_sii_read( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_sii_t data; fp@2433: const ec_slave_t *slave; fp@2433: int retval; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(slave = ec_master_find_slave_const( fp@2433: master, 0, data.slave_position))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave %u does not exist!\n", fp@2433: data.slave_position); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (!data.nwords fp@2433: || data.offset + data.nwords > slave->sii_nwords) { fp@2433: up(&master->master_sem); fp@2433: EC_SLAVE_ERR(slave, "Invalid SII read offset/size %u/%u for slave SII" fp@2433: " size %zu!\n", data.offset, data.nwords, slave->sii_nwords); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (copy_to_user((void __user *) data.words, fp@2433: slave->sii_words + data.offset, data.nwords * 2)) fp@2433: retval = -EFAULT; fp@2433: else fp@2433: retval = 0; fp@2433: fp@2433: up(&master->master_sem); fp@2433: return retval; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Write a slave's SII. fp@2433: */ fp@2433: static int ec_ioctl_slave_sii_write( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_sii_t data; fp@2433: ec_slave_t *slave; fp@2433: unsigned int byte_size; fp@2433: uint16_t *words; fp@2433: ec_sii_write_request_t request; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (!data.nwords) fp@2433: return 0; fp@2433: fp@2433: byte_size = sizeof(uint16_t) * data.nwords; fp@2433: if (!(words = kmalloc(byte_size, GFP_KERNEL))) { fp@2433: EC_MASTER_ERR(master, "Failed to allocate %u bytes" fp@2433: " for SII contents.\n", byte_size); fp@2433: return -ENOMEM; fp@2433: } fp@2433: fp@2433: if (copy_from_user(words, fp@2433: (void __user *) data.words, byte_size)) { fp@2433: kfree(words); fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(slave = ec_master_find_slave( fp@2433: master, 0, data.slave_position))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave %u does not exist!\n", fp@2433: data.slave_position); fp@2433: kfree(words); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: // init SII write request fp@2433: INIT_LIST_HEAD(&request.list); fp@2433: request.slave = slave; fp@2433: request.words = words; fp@2433: request.offset = data.offset; fp@2433: request.nwords = data.nwords; fp@2433: request.state = EC_INT_REQUEST_QUEUED; fp@2433: fp@2433: // schedule SII write request. fp@2433: list_add_tail(&request.list, &master->sii_requests); fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: // wait for processing through FSM fp@2433: if (wait_event_interruptible(master->sii_queue, fp@2433: request.state != EC_INT_REQUEST_QUEUED)) { fp@2433: // interrupted by signal fp@2433: down(&master->master_sem); fp@2433: if (request.state == EC_INT_REQUEST_QUEUED) { fp@2433: // abort request fp@2433: list_del(&request.list); fp@2433: up(&master->master_sem); fp@2433: kfree(words); fp@2433: return -EINTR; fp@2433: } fp@2433: up(&master->master_sem); fp@2433: } fp@2433: fp@2433: // wait until master FSM has finished processing fp@2433: wait_event(master->sii_queue, request.state != EC_INT_REQUEST_BUSY); fp@2433: fp@2433: kfree(words); fp@2433: fp@2433: return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Read a slave's registers. fp@2433: */ fp@2433: static int ec_ioctl_slave_reg_read( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_reg_t data; fp@2433: ec_slave_t *slave; fp@2433: uint8_t *contents; fp@2433: ec_reg_request_t request; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (!data.length) fp@2433: return 0; fp@2433: fp@2433: if (!(contents = kmalloc(data.length, GFP_KERNEL))) { fp@2433: EC_MASTER_ERR(master, "Failed to allocate %u bytes" fp@2433: " for register data.\n", data.length); fp@2433: return -ENOMEM; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(slave = ec_master_find_slave( fp@2433: master, 0, data.slave_position))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave %u does not exist!\n", fp@2433: data.slave_position); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: // init register request fp@2433: INIT_LIST_HEAD(&request.list); fp@2433: request.slave = slave; fp@2433: request.dir = EC_DIR_INPUT; fp@2433: request.data = contents; fp@2433: request.offset = data.offset; fp@2433: request.length = data.length; fp@2433: request.state = EC_INT_REQUEST_QUEUED; fp@2433: fp@2433: // schedule request. fp@2433: list_add_tail(&request.list, &master->reg_requests); fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: // wait for processing through FSM fp@2433: if (wait_event_interruptible(master->reg_queue, fp@2433: request.state != EC_INT_REQUEST_QUEUED)) { fp@2433: // interrupted by signal fp@2433: down(&master->master_sem); fp@2433: if (request.state == EC_INT_REQUEST_QUEUED) { fp@2433: // abort request fp@2433: list_del(&request.list); fp@2433: up(&master->master_sem); fp@2433: kfree(contents); fp@2433: return -EINTR; fp@2433: } fp@2433: up(&master->master_sem); fp@2433: } fp@2433: fp@2433: // wait until master FSM has finished processing fp@2433: wait_event(master->reg_queue, request.state != EC_INT_REQUEST_BUSY); fp@2433: fp@2433: if (request.state == EC_INT_REQUEST_SUCCESS) { fp@2433: if (copy_to_user((void __user *) data.data, contents, data.length)) fp@2433: return -EFAULT; fp@2433: } fp@2433: kfree(contents); fp@2433: fp@2433: return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Write a slave's registers. fp@2433: */ fp@2433: static int ec_ioctl_slave_reg_write( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_reg_t data; fp@2433: ec_slave_t *slave; fp@2433: uint8_t *contents; fp@2433: ec_reg_request_t request; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (!data.length) fp@2433: return 0; fp@2433: fp@2433: if (!(contents = kmalloc(data.length, GFP_KERNEL))) { fp@2433: EC_MASTER_ERR(master, "Failed to allocate %u bytes" fp@2433: " for register data.\n", data.length); fp@2433: return -ENOMEM; fp@2433: } fp@2433: fp@2433: if (copy_from_user(contents, (void __user *) data.data, data.length)) { fp@2433: kfree(contents); fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(slave = ec_master_find_slave( fp@2433: master, 0, data.slave_position))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave %u does not exist!\n", fp@2433: data.slave_position); fp@2433: kfree(contents); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: // init register request fp@2433: INIT_LIST_HEAD(&request.list); fp@2433: request.slave = slave; fp@2433: request.dir = EC_DIR_OUTPUT; fp@2433: request.data = contents; fp@2433: request.offset = data.offset; fp@2433: request.length = data.length; fp@2433: request.state = EC_INT_REQUEST_QUEUED; fp@2433: fp@2433: // schedule request. fp@2433: list_add_tail(&request.list, &master->reg_requests); fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: // wait for processing through FSM fp@2433: if (wait_event_interruptible(master->reg_queue, fp@2433: request.state != EC_INT_REQUEST_QUEUED)) { fp@2433: // interrupted by signal fp@2433: down(&master->master_sem); fp@2433: if (request.state == EC_INT_REQUEST_QUEUED) { fp@2433: // abort request fp@2433: list_del(&request.list); fp@2433: up(&master->master_sem); fp@2433: kfree(contents); fp@2433: return -EINTR; fp@2433: } fp@2433: up(&master->master_sem); fp@2433: } fp@2433: fp@2433: // wait until master FSM has finished processing fp@2433: wait_event(master->reg_queue, request.state != EC_INT_REQUEST_BUSY); fp@2433: fp@2433: kfree(contents); fp@2433: fp@2433: return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get slave configuration information. fp@2433: */ fp@2433: static int ec_ioctl_config( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_config_t data; fp@2433: const ec_slave_config_t *sc; fp@2433: uint8_t i; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(sc = ec_master_get_config_const( fp@2433: master, data.config_index))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave config %u does not exist!\n", fp@2433: data.config_index); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: data.alias = sc->alias; fp@2433: data.position = sc->position; fp@2433: data.vendor_id = sc->vendor_id; fp@2433: data.product_code = sc->product_code; fp@2433: for (i = 0; i < EC_MAX_SYNC_MANAGERS; i++) { fp@2433: data.syncs[i].dir = sc->sync_configs[i].dir; fp@2433: data.syncs[i].watchdog_mode = sc->sync_configs[i].watchdog_mode; fp@2433: data.syncs[i].pdo_count = fp@2433: ec_pdo_list_count(&sc->sync_configs[i].pdos); fp@2433: } fp@2433: data.watchdog_divider = sc->watchdog_divider; fp@2433: data.watchdog_intervals = sc->watchdog_intervals; fp@2433: data.sdo_count = ec_slave_config_sdo_count(sc); fp@2433: data.idn_count = ec_slave_config_idn_count(sc); fp@2433: data.slave_position = sc->slave ? sc->slave->ring_position : -1; fp@2433: data.dc_assign_activate = sc->dc_assign_activate; fp@2433: for (i = 0; i < EC_SYNC_SIGNAL_COUNT; i++) { fp@2433: data.dc_sync[i] = sc->dc_sync[i]; fp@2433: } fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get slave configuration PDO information. fp@2433: */ fp@2433: static int ec_ioctl_config_pdo( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_config_pdo_t data; fp@2433: const ec_slave_config_t *sc; fp@2433: const ec_pdo_t *pdo; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (data.sync_index >= EC_MAX_SYNC_MANAGERS) { fp@2433: EC_MASTER_ERR(master, "Invalid sync manager index %u!\n", fp@2433: data.sync_index); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(sc = ec_master_get_config_const( fp@2433: master, data.config_index))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave config %u does not exist!\n", fp@2433: data.config_index); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( fp@2433: &sc->sync_configs[data.sync_index].pdos, fp@2433: data.pdo_pos))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Invalid PDO position!\n"); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: data.index = pdo->index; fp@2433: data.entry_count = ec_pdo_entry_count(pdo); fp@2433: ec_ioctl_strcpy(data.name, pdo->name); fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get slave configuration PDO entry information. fp@2433: */ fp@2433: static int ec_ioctl_config_pdo_entry( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_config_pdo_entry_t data; fp@2433: const ec_slave_config_t *sc; fp@2433: const ec_pdo_t *pdo; fp@2433: const ec_pdo_entry_t *entry; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (data.sync_index >= EC_MAX_SYNC_MANAGERS) { fp@2433: EC_MASTER_ERR(master, "Invalid sync manager index %u!\n", fp@2433: data.sync_index); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(sc = ec_master_get_config_const( fp@2433: master, data.config_index))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave config %u does not exist!\n", fp@2433: data.config_index); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( fp@2433: &sc->sync_configs[data.sync_index].pdos, fp@2433: data.pdo_pos))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Invalid PDO position!\n"); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (!(entry = ec_pdo_find_entry_by_pos_const( fp@2433: pdo, data.entry_pos))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Entry not found!\n"); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: data.index = entry->index; fp@2433: data.subindex = entry->subindex; fp@2433: data.bit_length = entry->bit_length; fp@2433: ec_ioctl_strcpy(data.name, entry->name); fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get slave configuration SDO information. fp@2433: */ fp@2433: static int ec_ioctl_config_sdo( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_config_sdo_t *ioctl; fp@2433: const ec_slave_config_t *sc; fp@2433: const ec_sdo_request_t *req; fp@2433: fp@2433: if (!(ioctl = kmalloc(sizeof(*ioctl), GFP_KERNEL))) { fp@2433: return -ENOMEM; fp@2433: } fp@2433: fp@2433: if (copy_from_user(ioctl, (void __user *) arg, sizeof(*ioctl))) { fp@2433: kfree(ioctl); fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) { fp@2433: kfree(ioctl); fp@2433: return -EINTR; fp@2433: } fp@2433: fp@2433: if (!(sc = ec_master_get_config_const( fp@2433: master, ioctl->config_index))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave config %u does not exist!\n", fp@2433: ioctl->config_index); fp@2433: kfree(ioctl); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (!(req = ec_slave_config_get_sdo_by_pos_const( fp@2433: sc, ioctl->sdo_pos))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Invalid SDO position!\n"); fp@2433: kfree(ioctl); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: ioctl->index = req->index; fp@2433: ioctl->subindex = req->subindex; fp@2433: ioctl->size = req->data_size; fp@2433: memcpy(ioctl->data, req->data, fp@2433: min((u32) ioctl->size, (u32) EC_MAX_SDO_DATA_SIZE)); fp@2435: ioctl->complete_access = req->complete_access; fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, ioctl, sizeof(*ioctl))) { fp@2433: kfree(ioctl); fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: kfree(ioctl); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get slave configuration IDN information. fp@2433: */ fp@2433: static int ec_ioctl_config_idn( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_config_idn_t *ioctl; fp@2433: const ec_slave_config_t *sc; fp@2433: const ec_soe_request_t *req; fp@2433: fp@2433: if (!(ioctl = kmalloc(sizeof(*ioctl), GFP_KERNEL))) { fp@2433: return -ENOMEM; fp@2433: } fp@2433: fp@2433: if (copy_from_user(ioctl, (void __user *) arg, sizeof(*ioctl))) { fp@2433: kfree(ioctl); fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) { fp@2433: kfree(ioctl); fp@2433: return -EINTR; fp@2433: } fp@2433: fp@2433: if (!(sc = ec_master_get_config_const( fp@2433: master, ioctl->config_index))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave config %u does not exist!\n", fp@2433: ioctl->config_index); fp@2433: kfree(ioctl); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (!(req = ec_slave_config_get_idn_by_pos_const( fp@2433: sc, ioctl->idn_pos))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Invalid IDN position!\n"); fp@2433: kfree(ioctl); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: ioctl->drive_no = req->drive_no; fp@2433: ioctl->idn = req->idn; fp@2433: ioctl->state = req->state; fp@2433: ioctl->size = req->data_size; fp@2433: memcpy(ioctl->data, req->data, fp@2433: min((u32) ioctl->size, (u32) EC_MAX_IDN_DATA_SIZE)); fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, ioctl, sizeof(*ioctl))) { fp@2433: kfree(ioctl); fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: kfree(ioctl); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: #ifdef EC_EOE fp@2433: fp@2433: /** Get EoE handler information. fp@2433: */ fp@2433: static int ec_ioctl_eoe_handler( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_eoe_handler_t data; fp@2433: const ec_eoe_t *eoe; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(eoe = ec_master_get_eoe_handler_const(master, data.eoe_index))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "EoE handler %u does not exist!\n", fp@2433: data.eoe_index); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: if (eoe->slave) { fp@2433: data.slave_position = eoe->slave->ring_position; fp@2433: } else { fp@2433: data.slave_position = 0xffff; fp@2433: } fp@2433: snprintf(data.name, EC_DATAGRAM_NAME_SIZE, eoe->dev->name); fp@2433: data.open = eoe->opened; fp@2433: data.rx_bytes = eoe->stats.tx_bytes; fp@2433: data.rx_rate = eoe->tx_rate; fp@2433: data.tx_bytes = eoe->stats.rx_bytes; fp@2433: data.tx_rate = eoe->tx_rate; fp@2433: data.tx_queued_frames = eoe->tx_queued_frames; fp@2433: data.tx_queue_size = eoe->tx_queue_size; fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: #endif fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Request the master from userspace. fp@2433: */ fp@2433: static int ec_ioctl_request( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_master_t *m; fp@2433: int ret = 0; fp@2433: fp@2433: m = ecrt_request_master_err(master->index); fp@2433: if (IS_ERR(m)) { fp@2433: ret = PTR_ERR(m); fp@2433: } else { fp@2433: ctx->requested = 1; fp@2433: } fp@2433: fp@2433: return ret; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Create a domain. fp@2433: */ fp@2433: static int ec_ioctl_create_domain( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_domain_t *domain; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: domain = ecrt_master_create_domain_err(master); fp@2433: if (IS_ERR(domain)) fp@2433: return PTR_ERR(domain); fp@2433: fp@2433: return domain->index; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Create a slave configuration. fp@2433: */ fp@2433: static int ec_ioctl_create_slave_config( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_config_t data; fp@2433: ec_slave_config_t *sc, *entry; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: sc = ecrt_master_slave_config_err(master, data.alias, data.position, fp@2433: data.vendor_id, data.product_code); fp@2433: if (IS_ERR(sc)) fp@2433: return PTR_ERR(sc); fp@2433: fp@2433: data.config_index = 0; fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: list_for_each_entry(entry, &master->configs, list) { fp@2433: if (entry == sc) fp@2433: break; fp@2433: data.config_index++; fp@2433: } fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Activates the master. fp@2433: */ fp@2433: static int ec_ioctl_activate( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_master_activate_t io; fp@2433: ec_domain_t *domain; fp@2433: off_t offset; fp@2433: int ret; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: io.process_data = NULL; fp@2433: fp@2433: /* Get the sum of the domains' process data sizes. */ fp@2433: fp@2433: ctx->process_data_size = 0; fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: list_for_each_entry(domain, &master->domains, list) { fp@2433: ctx->process_data_size += ecrt_domain_size(domain); fp@2433: } fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: if (ctx->process_data_size) { fp@2433: ctx->process_data = vmalloc(ctx->process_data_size); fp@2433: if (!ctx->process_data) { fp@2433: ctx->process_data_size = 0; fp@2433: return -ENOMEM; fp@2433: } fp@2433: fp@2433: /* Set the memory as external process data memory for the fp@2433: * domains. fp@2433: */ fp@2433: offset = 0; fp@2433: list_for_each_entry(domain, &master->domains, list) { fp@2433: ecrt_domain_external_memory(domain, fp@2433: ctx->process_data + offset); fp@2433: offset += ecrt_domain_size(domain); fp@2433: } fp@2433: fp@2433: #ifdef EC_IOCTL_RTDM fp@2433: /* RTDM uses a different approach for memory-mapping, which has to be fp@2433: * initiated by the kernel. fp@2433: */ fp@2433: ret = ec_rtdm_mmap(ctx, &io.process_data); fp@2433: if (ret < 0) { fp@2433: EC_MASTER_ERR(master, "Failed to map process data" fp@2433: " memory to user space (code %i).\n", ret); fp@2433: return ret; fp@2433: } fp@2433: #endif fp@2433: } fp@2433: fp@2433: io.process_data_size = ctx->process_data_size; fp@2433: fp@2433: #ifndef EC_IOCTL_RTDM fp@2433: ecrt_master_callbacks(master, ec_master_internal_send_cb, fp@2433: ec_master_internal_receive_cb, master); fp@2433: #endif fp@2433: fp@2433: ret = ecrt_master_activate(master); fp@2433: if (ret < 0) fp@2433: return ret; fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &io, fp@2433: sizeof(ec_ioctl_master_activate_t))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Deactivates the master. fp@2433: */ fp@2433: static int ec_ioctl_deactivate( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: ecrt_master_deactivate(master); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Set max. number of databytes in a cycle fp@2433: */ fp@2433: static int ec_ioctl_set_send_interval( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: size_t send_interval; fp@2433: fp@2433: if (copy_from_user(&send_interval, (void __user *) arg, fp@2433: sizeof(send_interval))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: ec_master_set_send_interval(master, send_interval); fp@2433: fp@2433: up(&master->master_sem); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Send frames. fp@2433: */ fp@2433: static int ec_ioctl_send( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: down(&master->io_sem); fp@2433: ecrt_master_send(master); fp@2433: up(&master->io_sem); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Receive frames. fp@2433: */ fp@2433: static int ec_ioctl_receive( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: down(&master->io_sem); fp@2433: ecrt_master_receive(master); fp@2433: up(&master->io_sem); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get the master state. fp@2433: */ fp@2433: static int ec_ioctl_master_state( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_master_state_t data; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: ecrt_master_state(master, &data); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get the master state. fp@2433: */ fp@2433: static int ec_ioctl_master_link_state( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_link_state_t ioctl; fp@2433: ec_master_link_state_t state; fp@2433: int ret; fp@2433: fp@2433: if (unlikely(!ctx->requested)) { fp@2433: return -EPERM; fp@2433: } fp@2433: fp@2433: if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: ret = ecrt_master_link_state(master, ioctl.dev_idx, &state); fp@2433: if (ret < 0) { fp@2433: return ret; fp@2433: } fp@2433: fp@2433: if (copy_to_user((void __user *) ioctl.state, &state, sizeof(state))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Set the master dc app time. fp@2433: */ fp@2433: static int ec_ioctl_app_time( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_app_time_t data; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: ecrt_master_application_time(master, data.app_time); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Sync the reference clock. fp@2433: */ fp@2433: static int ec_ioctl_sync_ref( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: down(&master->io_sem); fp@2433: ecrt_master_sync_reference_clock(master); fp@2433: up(&master->io_sem); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Sync the slave clocks. fp@2433: */ fp@2433: static int ec_ioctl_sync_slaves( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: down(&master->io_sem); fp@2433: ecrt_master_sync_slave_clocks(master); fp@2433: up(&master->io_sem); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Queue the sync monitoring datagram. fp@2433: */ fp@2433: static int ec_ioctl_sync_mon_queue( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: down(&master->io_sem); fp@2433: ecrt_master_sync_monitor_queue(master); fp@2433: up(&master->io_sem); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Processes the sync monitoring datagram. fp@2433: */ fp@2433: static int ec_ioctl_sync_mon_process( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: uint32_t time_diff; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: down(&master->io_sem); fp@2433: time_diff = ecrt_master_sync_monitor_process(master); fp@2433: up(&master->io_sem); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &time_diff, sizeof(time_diff))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Reset configuration. fp@2433: */ fp@2433: static int ec_ioctl_reset( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: down(&master->master_sem); fp@2433: ecrt_master_reset(master); fp@2433: up(&master->master_sem); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Configure a sync manager. fp@2433: */ fp@2433: static int ec_ioctl_sc_sync( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_config_t data; fp@2433: ec_slave_config_t *sc; fp@2433: unsigned int i; fp@2433: int ret = 0; fp@2433: fp@2433: if (unlikely(!ctx->requested)) { fp@2433: ret = -EPERM; fp@2433: goto out_return; fp@2433: } fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: ret = -EFAULT; fp@2433: goto out_return; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) { fp@2433: ret = -EINTR; fp@2433: goto out_return; fp@2433: } fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: ret = -ENOENT; fp@2433: goto out_up; fp@2433: } fp@2433: fp@2433: for (i = 0; i < EC_MAX_SYNC_MANAGERS; i++) { fp@2433: if (data.syncs[i].config_this) { fp@2433: if (ecrt_slave_config_sync_manager(sc, i, data.syncs[i].dir, fp@2433: data.syncs[i].watchdog_mode)) { fp@2433: ret = -EINVAL; fp@2433: goto out_up; fp@2433: } fp@2433: } fp@2433: } fp@2433: fp@2433: out_up: fp@2433: up(&master->master_sem); fp@2433: out_return: fp@2433: return ret; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Configure a slave's watchdogs. fp@2433: */ fp@2433: static int ec_ioctl_sc_watchdog( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_config_t data; fp@2433: ec_slave_config_t *sc; fp@2433: int ret = 0; fp@2433: fp@2433: if (unlikely(!ctx->requested)) { fp@2433: ret = -EPERM; fp@2433: goto out_return; fp@2433: } fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: ret = -EFAULT; fp@2433: goto out_return; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) { fp@2433: ret = -EINTR; fp@2433: goto out_return; fp@2433: } fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: ret = -ENOENT; fp@2433: goto out_up; fp@2433: } fp@2433: fp@2433: ecrt_slave_config_watchdog(sc, fp@2433: data.watchdog_divider, data.watchdog_intervals); fp@2433: fp@2433: out_up: fp@2433: up(&master->master_sem); fp@2433: out_return: fp@2433: return ret; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Add a PDO to the assignment. fp@2433: */ fp@2433: static int ec_ioctl_sc_add_pdo( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_config_pdo_t data; fp@2433: ec_slave_config_t *sc; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: up(&master->master_sem); fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: up(&master->master_sem); /** \fixme sc could be invalidated */ fp@2433: fp@2433: return ecrt_slave_config_pdo_assign_add(sc, data.sync_index, data.index); fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Clears the PDO assignment. fp@2433: */ fp@2433: static int ec_ioctl_sc_clear_pdos( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_config_pdo_t data; fp@2433: ec_slave_config_t *sc; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: up(&master->master_sem); fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: up(&master->master_sem); /** \fixme sc could be invalidated */ fp@2433: fp@2433: ecrt_slave_config_pdo_assign_clear(sc, data.sync_index); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Add an entry to a PDO's mapping. fp@2433: */ fp@2433: static int ec_ioctl_sc_add_entry( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_add_pdo_entry_t data; fp@2433: ec_slave_config_t *sc; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: up(&master->master_sem); fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: up(&master->master_sem); /** \fixme sc could be invalidated */ fp@2433: fp@2433: return ecrt_slave_config_pdo_mapping_add(sc, data.pdo_index, fp@2433: data.entry_index, data.entry_subindex, data.entry_bit_length); fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Clears the mapping of a PDO. fp@2433: */ fp@2433: static int ec_ioctl_sc_clear_entries( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_config_pdo_t data; fp@2433: ec_slave_config_t *sc; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: up(&master->master_sem); fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: up(&master->master_sem); /** \fixme sc could be invalidated */ fp@2433: fp@2433: ecrt_slave_config_pdo_mapping_clear(sc, data.index); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Registers a PDO entry. fp@2433: */ fp@2433: static int ec_ioctl_sc_reg_pdo_entry( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_reg_pdo_entry_t data; fp@2433: ec_slave_config_t *sc; fp@2433: ec_domain_t *domain; fp@2433: int ret; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: up(&master->master_sem); fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: if (!(domain = ec_master_find_domain(master, data.domain_index))) { fp@2433: up(&master->master_sem); fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: up(&master->master_sem); /** \fixme sc or domain could be invalidated */ fp@2433: fp@2433: ret = ecrt_slave_config_reg_pdo_entry(sc, data.entry_index, fp@2433: data.entry_subindex, domain, &data.bit_position); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return ret; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Sets the DC AssignActivate word and the sync signal times. fp@2433: */ fp@2433: static int ec_ioctl_sc_dc( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_config_t data; fp@2433: ec_slave_config_t *sc; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: up(&master->master_sem); fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: ecrt_slave_config_dc(sc, data.dc_assign_activate, fp@2433: data.dc_sync[0].cycle_time, fp@2433: data.dc_sync[0].shift_time, fp@2433: data.dc_sync[1].cycle_time, fp@2433: data.dc_sync[1].shift_time); fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Configures an SDO. fp@2433: */ fp@2433: static int ec_ioctl_sc_sdo( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_sc_sdo_t data; fp@2433: ec_slave_config_t *sc; fp@2433: uint8_t *sdo_data = NULL; fp@2433: int ret; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: if (!data.size) fp@2433: return -EINVAL; fp@2433: fp@2433: if (!(sdo_data = kmalloc(data.size, GFP_KERNEL))) { fp@2433: return -ENOMEM; fp@2433: } fp@2433: fp@2433: if (copy_from_user(sdo_data, (void __user *) data.data, data.size)) { fp@2433: kfree(sdo_data); fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) { fp@2433: kfree(sdo_data); fp@2433: return -EINTR; fp@2433: } fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: up(&master->master_sem); fp@2433: kfree(sdo_data); fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: up(&master->master_sem); /** \fixme sc could be invalidated */ fp@2433: fp@2433: if (data.complete_access) { fp@2433: ret = ecrt_slave_config_complete_sdo(sc, fp@2433: data.index, sdo_data, data.size); fp@2433: } else { fp@2433: ret = ecrt_slave_config_sdo(sc, data.index, data.subindex, sdo_data, fp@2433: data.size); fp@2433: } fp@2433: kfree(sdo_data); fp@2433: return ret; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2438: /** Set the emergency ring buffer size. fp@2438: */ fp@2438: static int ec_ioctl_sc_emerg_size( fp@2438: ec_master_t *master, /**< EtherCAT master. */ fp@2438: void *arg, /**< ioctl() argument. */ fp@2438: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2438: ) fp@2438: { fp@2438: ec_ioctl_sc_emerg_t io; fp@2438: ec_slave_config_t *sc; fp@2438: int ret; fp@2438: fp@2438: if (unlikely(!ctx->requested)) fp@2438: return -EPERM; fp@2438: fp@2438: if (copy_from_user(&io, (void __user *) arg, sizeof(io))) fp@2438: return -EFAULT; fp@2438: fp@2438: if (down_interruptible(&master->master_sem)) { fp@2438: return -EINTR; fp@2438: } fp@2438: fp@2438: if (!(sc = ec_master_get_config(master, io.config_index))) { fp@2438: up(&master->master_sem); fp@2438: return -ENOENT; fp@2438: } fp@2438: fp@2438: ret = ecrt_slave_config_emerg_size(sc, io.size); fp@2438: fp@2438: up(&master->master_sem); fp@2438: fp@2438: return ret; fp@2438: } fp@2438: fp@2438: /*****************************************************************************/ fp@2438: fp@2438: /** Get an emergency message from the ring. fp@2438: */ fp@2438: static int ec_ioctl_sc_emerg_pop( fp@2438: ec_master_t *master, /**< EtherCAT master. */ fp@2438: void *arg, /**< ioctl() argument. */ fp@2438: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2438: ) fp@2438: { fp@2438: ec_ioctl_sc_emerg_t io; fp@2438: ec_slave_config_t *sc; fp@2438: u8 msg[EC_COE_EMERGENCY_MSG_SIZE]; fp@2438: int ret; fp@2438: fp@2438: if (unlikely(!ctx->requested)) fp@2438: return -EPERM; fp@2438: fp@2438: if (copy_from_user(&io, (void __user *) arg, sizeof(io))) fp@2438: return -EFAULT; fp@2438: fp@2438: if (down_interruptible(&master->master_sem)) { fp@2438: return -EINTR; fp@2438: } fp@2438: fp@2438: if (!(sc = ec_master_get_config(master, io.config_index))) { fp@2438: up(&master->master_sem); fp@2438: return -ENOENT; fp@2438: } fp@2438: fp@2438: ret = ecrt_slave_config_emerg_pop(sc, msg); fp@2438: fp@2438: up(&master->master_sem); fp@2438: fp@2438: if (ret < 0) { fp@2438: return ret; fp@2438: } fp@2438: fp@2438: if (copy_to_user((void __user *) io.target, msg, sizeof(msg))) { fp@2438: return -EFAULT; fp@2438: } fp@2438: fp@2438: return ret; fp@2438: } fp@2438: fp@2438: /*****************************************************************************/ fp@2438: fp@2438: /** Clear the emergency ring. fp@2438: */ fp@2438: static int ec_ioctl_sc_emerg_clear( fp@2438: ec_master_t *master, /**< EtherCAT master. */ fp@2438: void *arg, /**< ioctl() argument. */ fp@2438: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2438: ) fp@2438: { fp@2438: ec_ioctl_sc_emerg_t io; fp@2438: ec_slave_config_t *sc; fp@2438: int ret; fp@2438: fp@2438: if (unlikely(!ctx->requested)) fp@2438: return -EPERM; fp@2438: fp@2438: if (copy_from_user(&io, (void __user *) arg, sizeof(io))) fp@2438: return -EFAULT; fp@2438: fp@2438: if (down_interruptible(&master->master_sem)) { fp@2438: return -EINTR; fp@2438: } fp@2438: fp@2438: if (!(sc = ec_master_get_config(master, io.config_index))) { fp@2438: up(&master->master_sem); fp@2438: return -ENOENT; fp@2438: } fp@2438: fp@2438: ret = ecrt_slave_config_emerg_clear(sc); fp@2438: fp@2438: up(&master->master_sem); fp@2438: fp@2438: return ret; fp@2438: } fp@2438: fp@2438: /*****************************************************************************/ fp@2438: fp@2438: /** Get the number of emergency overruns. fp@2438: */ fp@2438: static int ec_ioctl_sc_emerg_overruns( fp@2438: ec_master_t *master, /**< EtherCAT master. */ fp@2438: void *arg, /**< ioctl() argument. */ fp@2438: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2438: ) fp@2438: { fp@2438: ec_ioctl_sc_emerg_t io; fp@2438: ec_slave_config_t *sc; fp@2438: int ret; fp@2438: fp@2438: if (unlikely(!ctx->requested)) fp@2438: return -EPERM; fp@2438: fp@2438: if (copy_from_user(&io, (void __user *) arg, sizeof(io))) fp@2438: return -EFAULT; fp@2438: fp@2438: if (down_interruptible(&master->master_sem)) { fp@2438: return -EINTR; fp@2438: } fp@2438: fp@2438: if (!(sc = ec_master_get_config(master, io.config_index))) { fp@2438: up(&master->master_sem); fp@2438: return -ENOENT; fp@2438: } fp@2438: fp@2438: ret = ecrt_slave_config_emerg_overruns(sc); fp@2438: fp@2438: up(&master->master_sem); fp@2438: fp@2438: if (ret < 0) { fp@2438: return ret; fp@2438: } fp@2438: fp@2438: io.overruns = ret; fp@2438: fp@2438: if (copy_to_user((void __user *) arg, &io, sizeof(io))) { fp@2438: return -EFAULT; fp@2438: } fp@2438: fp@2438: return 0; fp@2438: } fp@2438: fp@2438: /*****************************************************************************/ fp@2438: fp@2433: /** Create an SDO request. fp@2433: */ fp@2433: static int ec_ioctl_sc_create_sdo_request( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_sdo_request_t data; fp@2433: ec_slave_config_t *sc; fp@2433: ec_sdo_request_t *req; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: data.request_index = 0; fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: sc = ec_master_get_config(master, data.config_index); fp@2433: if (!sc) { fp@2433: up(&master->master_sem); fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: list_for_each_entry(req, &sc->sdo_requests, list) { fp@2433: data.request_index++; fp@2433: } fp@2433: fp@2433: up(&master->master_sem); /** \fixme sc could be invalidated */ fp@2433: fp@2433: req = ecrt_slave_config_create_sdo_request_err(sc, data.sdo_index, fp@2433: data.sdo_subindex, data.size); fp@2433: if (IS_ERR(req)) fp@2433: return PTR_ERR(req); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Create a VoE handler. fp@2433: */ fp@2433: static int ec_ioctl_sc_create_voe_handler( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_voe_t data; fp@2433: ec_slave_config_t *sc; fp@2433: ec_voe_handler_t *voe; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: data.voe_index = 0; fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) fp@2433: return -EINTR; fp@2433: fp@2433: sc = ec_master_get_config(master, data.config_index); fp@2433: if (!sc) { fp@2433: up(&master->master_sem); fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: list_for_each_entry(voe, &sc->voe_handlers, list) { fp@2433: data.voe_index++; fp@2433: } fp@2433: fp@2433: up(&master->master_sem); /** \fixme sc could be invalidated */ fp@2433: fp@2433: voe = ecrt_slave_config_create_voe_handler_err(sc, data.size); fp@2433: if (IS_ERR(voe)) fp@2433: return PTR_ERR(voe); fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get the slave configuration's state. fp@2433: */ fp@2433: static int ec_ioctl_sc_state( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_sc_state_t data; fp@2433: const ec_slave_config_t *sc; fp@2433: ec_slave_config_state_t state; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: /* no locking of master_sem needed, because sc will not be deleted in the fp@2433: * meantime. */ fp@2433: fp@2433: if (!(sc = ec_master_get_config_const(master, data.config_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: ecrt_slave_config_state(sc, &state); fp@2433: fp@2433: if (copy_to_user((void __user *) data.state, &state, sizeof(state))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Configures an IDN. fp@2433: */ fp@2433: static int ec_ioctl_sc_idn( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_sc_idn_t ioctl; fp@2433: ec_slave_config_t *sc; fp@2433: uint8_t *data = NULL; fp@2433: int ret; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl))) fp@2433: return -EFAULT; fp@2433: fp@2433: if (!ioctl.size) fp@2433: return -EINVAL; fp@2433: fp@2433: if (!(data = kmalloc(ioctl.size, GFP_KERNEL))) { fp@2433: return -ENOMEM; fp@2433: } fp@2433: fp@2433: if (copy_from_user(data, (void __user *) ioctl.data, ioctl.size)) { fp@2433: kfree(data); fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) { fp@2433: kfree(data); fp@2433: return -EINTR; fp@2433: } fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, ioctl.config_index))) { fp@2433: up(&master->master_sem); fp@2433: kfree(data); fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: up(&master->master_sem); /** \fixme sc could be invalidated */ fp@2433: fp@2433: ret = ecrt_slave_config_idn( fp@2433: sc, ioctl.drive_no, ioctl.idn, ioctl.al_state, data, ioctl.size); fp@2433: kfree(data); fp@2433: return ret; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Gets the domain's offset in the total process data. fp@2433: */ fp@2433: static int ec_ioctl_domain_offset( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: int offset = 0; fp@2433: const ec_domain_t *domain; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) { fp@2433: return -EINTR; fp@2433: } fp@2433: fp@2433: list_for_each_entry(domain, &master->domains, list) { fp@2433: if (domain->index == (unsigned int) arg) { fp@2433: up(&master->master_sem); fp@2433: return offset; fp@2433: } fp@2433: offset += ecrt_domain_size(domain); fp@2433: } fp@2433: fp@2433: up(&master->master_sem); fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Process the domain. fp@2433: */ fp@2433: static int ec_ioctl_domain_process( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_domain_t *domain; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: /* no locking of master_sem needed, because domain will not be deleted in fp@2433: * the meantime. */ fp@2433: fp@2433: if (!(domain = ec_master_find_domain(master, (unsigned int) arg))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: ecrt_domain_process(domain); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Queue the domain. fp@2433: */ fp@2433: static int ec_ioctl_domain_queue( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_domain_t *domain; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: /* no locking of master_sem needed, because domain will not be deleted in fp@2433: * the meantime. */ fp@2433: fp@2433: if (!(domain = ec_master_find_domain(master, (unsigned int) arg))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: ecrt_domain_queue(domain); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Get the domain state. fp@2433: */ fp@2433: static int ec_ioctl_domain_state( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_domain_state_t data; fp@2433: const ec_domain_t *domain; fp@2433: ec_domain_state_t state; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: /* no locking of master_sem needed, because domain will not be deleted in fp@2433: * the meantime. */ fp@2433: fp@2433: if (!(domain = ec_master_find_domain_const(master, data.domain_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: ecrt_domain_state(domain, &state); fp@2433: fp@2433: if (copy_to_user((void __user *) data.state, &state, sizeof(state))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2434: /** Sets an SDO request's SDO index and subindex. fp@2434: */ fp@2434: static int ec_ioctl_sdo_request_index( fp@2434: ec_master_t *master, /**< EtherCAT master. */ fp@2434: void *arg, /**< ioctl() argument. */ fp@2434: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2434: ) fp@2434: { fp@2434: ec_ioctl_sdo_request_t data; fp@2434: ec_slave_config_t *sc; fp@2434: ec_sdo_request_t *req; fp@2434: fp@2434: if (unlikely(!ctx->requested)) fp@2434: return -EPERM; fp@2434: fp@2434: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2434: return -EFAULT; fp@2434: fp@2434: /* no locking of master_sem needed, because neither sc nor req will not be fp@2434: * deleted in the meantime. */ fp@2434: fp@2434: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2434: return -ENOENT; fp@2434: } fp@2434: fp@2434: if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { fp@2434: return -ENOENT; fp@2434: } fp@2434: fp@2434: ecrt_sdo_request_index(req, data.sdo_index, data.sdo_subindex); fp@2434: return 0; fp@2434: } fp@2434: fp@2434: /*****************************************************************************/ fp@2434: fp@2433: /** Sets an SDO request's timeout. fp@2433: */ fp@2433: static int ec_ioctl_sdo_request_timeout( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_sdo_request_t data; fp@2433: ec_slave_config_t *sc; fp@2433: ec_sdo_request_t *req; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: /* no locking of master_sem needed, because neither sc nor req will not be fp@2433: * deleted in the meantime. */ fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: ecrt_sdo_request_timeout(req, data.timeout); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Gets an SDO request's state. fp@2433: */ fp@2433: static int ec_ioctl_sdo_request_state( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_sdo_request_t data; fp@2433: ec_slave_config_t *sc; fp@2433: ec_sdo_request_t *req; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: /* no locking of master_sem needed, because neither sc nor req will not be fp@2433: * deleted in the meantime. */ fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: data.state = ecrt_sdo_request_state(req); fp@2433: if (data.state == EC_REQUEST_SUCCESS && req->dir == EC_DIR_INPUT) fp@2433: data.size = ecrt_sdo_request_data_size(req); fp@2433: else fp@2433: data.size = 0; fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Starts an SDO read operation. fp@2433: */ fp@2433: static int ec_ioctl_sdo_request_read( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_sdo_request_t data; fp@2433: ec_slave_config_t *sc; fp@2433: ec_sdo_request_t *req; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: /* no locking of master_sem needed, because neither sc nor req will not be fp@2433: * deleted in the meantime. */ fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: ecrt_sdo_request_read(req); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Starts an SDO write operation. fp@2433: */ fp@2433: static int ec_ioctl_sdo_request_write( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_sdo_request_t data; fp@2433: ec_slave_config_t *sc; fp@2433: ec_sdo_request_t *req; fp@2433: int ret; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: if (!data.size) { fp@2433: EC_MASTER_ERR(master, "SDO download: Data size may not be zero!\n"); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: /* no locking of master_sem needed, because neither sc nor req will not be fp@2433: * deleted in the meantime. */ fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: ret = ec_sdo_request_alloc(req, data.size); fp@2433: if (ret) fp@2433: return ret; fp@2433: fp@2433: if (copy_from_user(req->data, (void __user *) data.data, data.size)) fp@2433: return -EFAULT; fp@2433: fp@2433: req->data_size = data.size; fp@2433: ecrt_sdo_request_write(req); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Read SDO data. fp@2433: */ fp@2433: static int ec_ioctl_sdo_request_data( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_sdo_request_t data; fp@2433: ec_slave_config_t *sc; fp@2433: ec_sdo_request_t *req; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: /* no locking of master_sem needed, because neither sc nor req will not be fp@2433: * deleted in the meantime. */ fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: if (copy_to_user((void __user *) data.data, ecrt_sdo_request_data(req), fp@2433: ecrt_sdo_request_data_size(req))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Sets the VoE send header. fp@2433: */ fp@2433: static int ec_ioctl_voe_send_header( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_voe_t data; fp@2433: ec_slave_config_t *sc; fp@2433: ec_voe_handler_t *voe; fp@2433: uint32_t vendor_id; fp@2433: uint16_t vendor_type; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: if (get_user(vendor_id, data.vendor_id)) fp@2433: return -EFAULT; fp@2433: fp@2433: if (get_user(vendor_type, data.vendor_type)) fp@2433: return -EFAULT; fp@2433: fp@2433: /* no locking of master_sem needed, because neither sc nor voe will not be fp@2433: * deleted in the meantime. */ fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: ecrt_voe_handler_send_header(voe, vendor_id, vendor_type); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Gets the received VoE header. fp@2433: */ fp@2433: static int ec_ioctl_voe_rec_header( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_voe_t data; fp@2433: ec_slave_config_t *sc; fp@2433: ec_voe_handler_t *voe; fp@2433: uint32_t vendor_id; fp@2433: uint16_t vendor_type; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: /* no locking of master_sem needed, because neither sc nor voe will not be fp@2433: * deleted in the meantime. */ fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: ecrt_voe_handler_received_header(voe, &vendor_id, &vendor_type); fp@2433: fp@2433: if (likely(data.vendor_id)) fp@2433: if (put_user(vendor_id, data.vendor_id)) fp@2433: return -EFAULT; fp@2433: fp@2433: if (likely(data.vendor_type)) fp@2433: if (put_user(vendor_type, data.vendor_type)) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Starts a VoE read operation. fp@2433: */ fp@2433: static int ec_ioctl_voe_read( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_voe_t data; fp@2433: ec_slave_config_t *sc; fp@2433: ec_voe_handler_t *voe; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: /* no locking of master_sem needed, because neither sc nor voe will not be fp@2433: * deleted in the meantime. */ fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: ecrt_voe_handler_read(voe); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Starts a VoE read operation without sending a sync message first. fp@2433: */ fp@2433: static int ec_ioctl_voe_read_nosync( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_voe_t data; fp@2433: ec_slave_config_t *sc; fp@2433: ec_voe_handler_t *voe; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: /* no locking of master_sem needed, because neither sc nor voe will not be fp@2433: * deleted in the meantime. */ fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: ecrt_voe_handler_read_nosync(voe); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Starts a VoE write operation. fp@2433: */ fp@2433: static int ec_ioctl_voe_write( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_voe_t data; fp@2433: ec_slave_config_t *sc; fp@2433: ec_voe_handler_t *voe; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: /* no locking of master_sem needed, because neither sc nor voe will not be fp@2433: * deleted in the meantime. */ fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: if (data.size) { fp@2433: if (data.size > ec_voe_handler_mem_size(voe)) fp@2433: return -EOVERFLOW; fp@2433: fp@2433: if (copy_from_user(ecrt_voe_handler_data(voe), fp@2433: (void __user *) data.data, data.size)) fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: ecrt_voe_handler_write(voe, data.size); fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Executes the VoE state machine. fp@2433: */ fp@2433: static int ec_ioctl_voe_exec( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_voe_t data; fp@2433: ec_slave_config_t *sc; fp@2433: ec_voe_handler_t *voe; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: /* no locking of master_sem needed, because neither sc nor voe will not be fp@2433: * deleted in the meantime. */ fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: data.state = ecrt_voe_handler_execute(voe); fp@2433: if (data.state == EC_REQUEST_SUCCESS && voe->dir == EC_DIR_INPUT) fp@2433: data.size = ecrt_voe_handler_data_size(voe); fp@2433: else fp@2433: data.size = 0; fp@2433: fp@2433: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Reads the received VoE data. fp@2433: */ fp@2433: static int ec_ioctl_voe_data( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg, /**< ioctl() argument. */ fp@2433: ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_voe_t data; fp@2433: ec_slave_config_t *sc; fp@2433: ec_voe_handler_t *voe; fp@2433: fp@2433: if (unlikely(!ctx->requested)) fp@2433: return -EPERM; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@2433: return -EFAULT; fp@2433: fp@2433: /* no locking of master_sem needed, because neither sc nor voe will not be fp@2433: * deleted in the meantime. */ fp@2433: fp@2433: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { fp@2433: return -ENOENT; fp@2433: } fp@2433: fp@2433: if (copy_to_user((void __user *) data.data, ecrt_voe_handler_data(voe), fp@2433: ecrt_voe_handler_data_size(voe))) fp@2433: return -EFAULT; fp@2433: fp@2433: return 0; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Read a file from a slave via FoE. fp@2433: */ fp@2433: static int ec_ioctl_slave_foe_read( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_foe_t data; fp@2433: ec_master_foe_request_t request; fp@2433: int retval; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: ec_foe_request_init(&request.req, data.file_name); fp@2433: ec_foe_request_read(&request.req); fp@2433: ec_foe_request_alloc(&request.req, 10000); // FIXME fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) { fp@2433: ec_foe_request_clear(&request.req); fp@2433: return -EINTR; fp@2433: } fp@2433: fp@2433: if (!(request.slave = ec_master_find_slave( fp@2433: master, 0, data.slave_position))) { fp@2433: up(&master->master_sem); fp@2433: ec_foe_request_clear(&request.req); fp@2433: EC_MASTER_ERR(master, "Slave %u does not exist!\n", fp@2433: data.slave_position); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: // schedule request. fp@2433: list_add_tail(&request.list, &request.slave->foe_requests); fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: EC_SLAVE_DBG(request.slave, 1, "Scheduled FoE read request.\n"); fp@2433: fp@2433: // wait for processing through FSM fp@2433: if (wait_event_interruptible(request.slave->foe_queue, fp@2433: request.req.state != EC_INT_REQUEST_QUEUED)) { fp@2433: // interrupted by signal fp@2433: down(&master->master_sem); fp@2433: if (request.req.state == EC_INT_REQUEST_QUEUED) { fp@2433: list_del(&request.list); fp@2433: up(&master->master_sem); fp@2433: ec_foe_request_clear(&request.req); fp@2433: return -EINTR; fp@2433: } fp@2433: // request already processing: interrupt not possible. fp@2433: up(&master->master_sem); fp@2433: } fp@2433: fp@2433: // wait until master FSM has finished processing fp@2433: wait_event(request.slave->foe_queue, fp@2433: request.req.state != EC_INT_REQUEST_BUSY); fp@2433: fp@2433: data.result = request.req.result; fp@2433: data.error_code = request.req.error_code; fp@2433: fp@2433: EC_SLAVE_DBG(request.slave, 1, "Read %zd bytes via FoE" fp@2433: " (result = 0x%x).\n", request.req.data_size, request.req.result); fp@2433: fp@2433: if (request.req.state != EC_INT_REQUEST_SUCCESS) { fp@2433: data.data_size = 0; fp@2433: retval = -EIO; fp@2433: } else { fp@2433: if (request.req.data_size > data.buffer_size) { fp@2433: EC_MASTER_ERR(master, "Buffer too small.\n"); fp@2433: ec_foe_request_clear(&request.req); fp@2433: return -EOVERFLOW; fp@2433: } fp@2433: data.data_size = request.req.data_size; fp@2433: if (copy_to_user((void __user *) data.buffer, fp@2433: request.req.buffer, data.data_size)) { fp@2433: ec_foe_request_clear(&request.req); fp@2433: return -EFAULT; fp@2433: } fp@2433: retval = 0; fp@2433: } fp@2433: fp@2433: if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { fp@2433: retval = -EFAULT; fp@2433: } fp@2433: fp@2433: EC_SLAVE_DBG(request.slave, 1, "Finished FoE read request.\n"); fp@2433: fp@2433: ec_foe_request_clear(&request.req); fp@2433: fp@2433: return retval; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Write a file to a slave via FoE fp@2433: */ fp@2433: static int ec_ioctl_slave_foe_write( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_foe_t data; fp@2433: ec_master_foe_request_t request; fp@2433: int retval; fp@2433: fp@2433: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: INIT_LIST_HEAD(&request.list); fp@2433: fp@2433: ec_foe_request_init(&request.req, data.file_name); fp@2433: fp@2433: if (ec_foe_request_alloc(&request.req, data.buffer_size)) { fp@2433: ec_foe_request_clear(&request.req); fp@2433: return -ENOMEM; fp@2433: } fp@2433: if (copy_from_user(request.req.buffer, fp@2433: (void __user *) data.buffer, data.buffer_size)) { fp@2433: ec_foe_request_clear(&request.req); fp@2433: return -EFAULT; fp@2433: } fp@2433: request.req.data_size = data.buffer_size; fp@2433: ec_foe_request_write(&request.req); fp@2433: fp@2433: if (down_interruptible(&master->master_sem)) { fp@2433: ec_foe_request_clear(&request.req); fp@2433: return -EINTR; fp@2433: } fp@2433: fp@2433: if (!(request.slave = ec_master_find_slave( fp@2433: master, 0, data.slave_position))) { fp@2433: up(&master->master_sem); fp@2433: EC_MASTER_ERR(master, "Slave %u does not exist!\n", fp@2433: data.slave_position); fp@2433: ec_foe_request_clear(&request.req); fp@2433: return -EINVAL; fp@2433: } fp@2433: fp@2433: EC_SLAVE_DBG(request.slave, 1, "Scheduling FoE write request.\n"); fp@2433: fp@2433: // schedule FoE write request. fp@2433: list_add_tail(&request.list, &request.slave->foe_requests); fp@2433: fp@2433: up(&master->master_sem); fp@2433: fp@2433: // wait for processing through FSM fp@2433: if (wait_event_interruptible(request.slave->foe_queue, fp@2433: request.req.state != EC_INT_REQUEST_QUEUED)) { fp@2433: // interrupted by signal fp@2433: down(&master->master_sem); fp@2433: if (request.req.state == EC_INT_REQUEST_QUEUED) { fp@2433: // abort request fp@2433: list_del(&request.list); fp@2433: up(&master->master_sem); fp@2433: ec_foe_request_clear(&request.req); fp@2433: return -EINTR; fp@2433: } fp@2433: up(&master->master_sem); fp@2433: } fp@2433: fp@2433: // wait until master FSM has finished processing fp@2433: wait_event(request.slave->foe_queue, fp@2433: request.req.state != EC_INT_REQUEST_BUSY); fp@2433: fp@2433: data.result = request.req.result; fp@2433: data.error_code = request.req.error_code; fp@2433: fp@2433: retval = request.req.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; fp@2433: fp@2433: if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { fp@2433: retval = -EFAULT; fp@2433: } fp@2433: fp@2433: ec_foe_request_clear(&request.req); fp@2433: fp@2433: EC_SLAVE_DBG(request.slave, 1, "Finished FoE write request.\n"); fp@2433: fp@2433: return retval; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Read an SoE IDN. fp@2433: */ fp@2433: static int ec_ioctl_slave_soe_read( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_soe_read_t ioctl; fp@2433: u8 *data; fp@2433: int retval; fp@2433: fp@2433: if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: data = kmalloc(ioctl.mem_size, GFP_KERNEL); fp@2433: if (!data) { fp@2433: EC_MASTER_ERR(master, "Failed to allocate %u bytes of IDN data.\n", fp@2433: ioctl.mem_size); fp@2433: return -ENOMEM; fp@2433: } fp@2433: fp@2433: retval = ecrt_master_read_idn(master, ioctl.slave_position, fp@2433: ioctl.drive_no, ioctl.idn, data, ioctl.mem_size, &ioctl.data_size, fp@2433: &ioctl.error_code); fp@2433: if (retval) { fp@2433: kfree(data); fp@2433: return retval; fp@2433: } fp@2433: fp@2433: if (copy_to_user((void __user *) ioctl.data, fp@2433: data, ioctl.data_size)) { fp@2433: kfree(data); fp@2433: return -EFAULT; fp@2433: } fp@2433: kfree(data); fp@2433: fp@2433: if (__copy_to_user((void __user *) arg, &ioctl, sizeof(ioctl))) { fp@2433: retval = -EFAULT; fp@2433: } fp@2433: fp@2433: EC_MASTER_DBG(master, 1, "Finished SoE read request.\n"); fp@2433: return retval; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: /** Write an IDN to a slave via SoE. fp@2433: */ fp@2433: static int ec_ioctl_slave_soe_write( fp@2433: ec_master_t *master, /**< EtherCAT master. */ fp@2433: void *arg /**< ioctl() argument. */ fp@2433: ) fp@2433: { fp@2433: ec_ioctl_slave_soe_write_t ioctl; fp@2433: u8 *data; fp@2433: int retval; fp@2433: fp@2433: if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl))) { fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: data = kmalloc(ioctl.data_size, GFP_KERNEL); fp@2433: if (!data) { fp@2433: EC_MASTER_ERR(master, "Failed to allocate %zu bytes of IDN data.\n", fp@2433: ioctl.data_size); fp@2433: return -ENOMEM; fp@2433: } fp@2433: if (copy_from_user(data, (void __user *) ioctl.data, ioctl.data_size)) { fp@2433: kfree(data); fp@2433: return -EFAULT; fp@2433: } fp@2433: fp@2433: retval = ecrt_master_write_idn(master, ioctl.slave_position, fp@2433: ioctl.drive_no, ioctl.idn, data, ioctl.data_size, fp@2433: &ioctl.error_code); fp@2433: kfree(data); fp@2433: if (retval) { fp@2433: return retval; fp@2433: } fp@2433: fp@2433: if (__copy_to_user((void __user *) arg, &ioctl, sizeof(ioctl))) { fp@2433: retval = -EFAULT; fp@2433: } fp@2433: fp@2433: EC_MASTER_DBG(master, 1, "Finished SoE write request.\n"); fp@2433: return retval; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/ fp@2433: fp@2433: #ifdef EC_IOCTL_RTDM fp@2433: #define EC_IOCTL ec_ioctl_rtdm fp@2433: #else fp@2433: #define EC_IOCTL ec_ioctl fp@2433: #endif fp@2433: fp@2433: /** Called when an ioctl() command is issued. fp@2433: */ fp@2433: long EC_IOCTL(ec_master_t *master, ec_ioctl_context_t *ctx, fp@2433: unsigned int cmd, void *arg) fp@2433: { fp@2433: #if DEBUG_LATENCY fp@2433: cycles_t a = get_cycles(), b; fp@2433: unsigned int t; fp@2433: #endif fp@2433: int ret; fp@2433: fp@2433: switch (cmd) { fp@2433: case EC_IOCTL_MODULE: fp@2433: ret = ec_ioctl_module(arg); fp@2433: break; fp@2433: case EC_IOCTL_MASTER: fp@2433: ret = ec_ioctl_master(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE: fp@2433: ret = ec_ioctl_slave(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE_SYNC: fp@2433: ret = ec_ioctl_slave_sync(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE_SYNC_PDO: fp@2433: ret = ec_ioctl_slave_sync_pdo(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE_SYNC_PDO_ENTRY: fp@2433: ret = ec_ioctl_slave_sync_pdo_entry(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_DOMAIN: fp@2433: ret = ec_ioctl_domain(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_DOMAIN_FMMU: fp@2433: ret = ec_ioctl_domain_fmmu(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_DOMAIN_DATA: fp@2433: ret = ec_ioctl_domain_data(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_MASTER_DEBUG: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_master_debug(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_MASTER_RESCAN: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_master_rescan(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE_STATE: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_slave_state(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE_SDO: fp@2433: ret = ec_ioctl_slave_sdo(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE_SDO_ENTRY: fp@2433: ret = ec_ioctl_slave_sdo_entry(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE_SDO_UPLOAD: fp@2433: ret = ec_ioctl_slave_sdo_upload(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE_SDO_DOWNLOAD: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_slave_sdo_download(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE_SII_READ: fp@2433: ret = ec_ioctl_slave_sii_read(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE_SII_WRITE: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_slave_sii_write(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE_REG_READ: fp@2433: ret = ec_ioctl_slave_reg_read(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE_REG_WRITE: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_slave_reg_write(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE_FOE_READ: fp@2433: ret = ec_ioctl_slave_foe_read(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE_FOE_WRITE: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_slave_foe_write(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE_SOE_READ: fp@2433: ret = ec_ioctl_slave_soe_read(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_SLAVE_SOE_WRITE: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_slave_soe_write(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_CONFIG: fp@2433: ret = ec_ioctl_config(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_CONFIG_PDO: fp@2433: ret = ec_ioctl_config_pdo(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_CONFIG_PDO_ENTRY: fp@2433: ret = ec_ioctl_config_pdo_entry(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_CONFIG_SDO: fp@2433: ret = ec_ioctl_config_sdo(master, arg); fp@2433: break; fp@2433: case EC_IOCTL_CONFIG_IDN: fp@2433: ret = ec_ioctl_config_idn(master, arg); fp@2433: break; fp@2433: #ifdef EC_EOE fp@2433: case EC_IOCTL_EOE_HANDLER: fp@2433: ret = ec_ioctl_eoe_handler(master, arg); fp@2433: break; fp@2433: #endif fp@2433: case EC_IOCTL_REQUEST: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_request(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_CREATE_DOMAIN: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_create_domain(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_CREATE_SLAVE_CONFIG: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_create_slave_config(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_ACTIVATE: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_activate(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_DEACTIVATE: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_deactivate(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SEND: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_send(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_RECEIVE: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_receive(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_MASTER_STATE: fp@2433: ret = ec_ioctl_master_state(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_MASTER_LINK_STATE: fp@2433: ret = ec_ioctl_master_link_state(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_APP_TIME: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_app_time(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SYNC_REF: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sync_ref(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SYNC_SLAVES: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sync_slaves(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SYNC_MON_QUEUE: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sync_mon_queue(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SYNC_MON_PROCESS: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sync_mon_process(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_RESET: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_reset(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SC_SYNC: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sc_sync(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SC_WATCHDOG: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sc_watchdog(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SC_ADD_PDO: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sc_add_pdo(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SC_CLEAR_PDOS: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sc_clear_pdos(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SC_ADD_ENTRY: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sc_add_entry(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SC_CLEAR_ENTRIES: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sc_clear_entries(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SC_REG_PDO_ENTRY: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sc_reg_pdo_entry(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SC_DC: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sc_dc(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SC_SDO: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sc_sdo(master, arg, ctx); fp@2433: break; fp@2438: case EC_IOCTL_SC_EMERG_SIZE: fp@2438: if (!ctx->writable) { fp@2438: ret = -EPERM; fp@2438: break; fp@2438: } fp@2438: ret = ec_ioctl_sc_emerg_size(master, arg, ctx); fp@2438: break; fp@2438: case EC_IOCTL_SC_EMERG_POP: fp@2438: if (!ctx->writable) { fp@2438: ret = -EPERM; fp@2438: break; fp@2438: } fp@2438: ret = ec_ioctl_sc_emerg_pop(master, arg, ctx); fp@2438: break; fp@2438: case EC_IOCTL_SC_EMERG_CLEAR: fp@2438: if (!ctx->writable) { fp@2438: ret = -EPERM; fp@2438: break; fp@2438: } fp@2438: ret = ec_ioctl_sc_emerg_clear(master, arg, ctx); fp@2438: break; fp@2438: case EC_IOCTL_SC_EMERG_OVERRUNS: fp@2438: if (!ctx->writable) { fp@2438: ret = -EPERM; fp@2438: break; fp@2438: } fp@2438: ret = ec_ioctl_sc_emerg_overruns(master, arg, ctx); fp@2438: break; fp@2433: case EC_IOCTL_SC_SDO_REQUEST: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sc_create_sdo_request(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SC_VOE: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sc_create_voe_handler(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SC_STATE: fp@2433: ret = ec_ioctl_sc_state(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SC_IDN: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sc_idn(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_DOMAIN_OFFSET: fp@2433: ret = ec_ioctl_domain_offset(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_DOMAIN_PROCESS: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_domain_process(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_DOMAIN_QUEUE: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_domain_queue(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_DOMAIN_STATE: fp@2433: ret = ec_ioctl_domain_state(master, arg, ctx); fp@2433: break; fp@2434: case EC_IOCTL_SDO_REQUEST_INDEX: fp@2434: if (!ctx->writable) { fp@2434: ret = -EPERM; fp@2434: break; fp@2434: } fp@2434: ret = ec_ioctl_sdo_request_index(master, arg, ctx); fp@2434: break; fp@2433: case EC_IOCTL_SDO_REQUEST_TIMEOUT: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sdo_request_timeout(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SDO_REQUEST_STATE: fp@2433: ret = ec_ioctl_sdo_request_state(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SDO_REQUEST_READ: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sdo_request_read(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SDO_REQUEST_WRITE: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_sdo_request_write(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SDO_REQUEST_DATA: fp@2433: ret = ec_ioctl_sdo_request_data(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_VOE_SEND_HEADER: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_voe_send_header(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_VOE_REC_HEADER: fp@2433: ret = ec_ioctl_voe_rec_header(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_VOE_READ: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_voe_read(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_VOE_READ_NOSYNC: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_voe_read_nosync(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_VOE_WRITE: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_voe_write(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_VOE_EXEC: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_voe_exec(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_VOE_DATA: fp@2433: ret = ec_ioctl_voe_data(master, arg, ctx); fp@2433: break; fp@2433: case EC_IOCTL_SET_SEND_INTERVAL: fp@2433: if (!ctx->writable) { fp@2433: ret = -EPERM; fp@2433: break; fp@2433: } fp@2433: ret = ec_ioctl_set_send_interval(master, arg, ctx); fp@2433: break; fp@2433: default: fp@2433: ret = -ENOTTY; fp@2433: break; fp@2433: } fp@2433: fp@2433: #if DEBUG_LATENCY fp@2433: b = get_cycles(); fp@2433: t = (unsigned int) ((b - a) * 1000LL) / cpu_khz; fp@2433: if (t > 50) { fp@2433: EC_MASTER_WARN(master, "ioctl(0x%02x) took %u us.\n", fp@2433: _IOC_NR(cmd), t); fp@2433: } fp@2433: #endif fp@2433: fp@2433: return ret; fp@2433: } fp@2433: fp@2433: /*****************************************************************************/