fp@922: /****************************************************************************** fp@922: * fp@922: * $Id$ fp@922: * fp@1326: * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH fp@922: * fp@922: * This file is part of the IgH EtherCAT Master. fp@922: * fp@1326: * The IgH EtherCAT Master is free software; you can redistribute it and/or fp@1326: * modify it under the terms of the GNU General Public License version 2, as fp@1326: * published by the Free Software Foundation. fp@922: * fp@1326: * The IgH EtherCAT Master is distributed in the hope that it will be useful, fp@1326: * but WITHOUT ANY WARRANTY; without even the implied warranty of fp@1326: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General fp@1326: * Public License for more details. fp@922: * fp@1326: * You should have received a copy of the GNU General Public License along fp@1326: * with the IgH EtherCAT Master; if not, write to the Free Software fp@922: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@922: * fp@1363: * --- fp@1363: * fp@1363: * The license mentioned above concerns the source code only. Using the fp@1363: * EtherCAT technology and brand is only permitted in compliance with the fp@1363: * industrial property and similar rights of Beckhoff Automation GmbH. fp@922: * fp@922: *****************************************************************************/ fp@922: fp@922: /** fp@922: \file fp@922: EtherCAT master character device. fp@922: */ fp@922: fp@922: /*****************************************************************************/ fp@922: fp@922: #include fp@1258: #include fp@1258: #include fp@922: fp@922: #include "cdev.h" fp@922: #include "master.h" fp@950: #include "slave_config.h" fp@1264: #include "voe_handler.h" fp@1485: #include "ethernet.h" fp@922: #include "ioctl.h" fp@922: fp@1465: /** Set to 1 to enable ioctl() command debugging. fp@1465: */ fp@1397: #define DEBUG_IOCTL 0 fp@1397: fp@922: /*****************************************************************************/ fp@922: fp@1268: static int eccdev_open(struct inode *, struct file *); fp@1268: static int eccdev_release(struct inode *, struct file *); fp@1268: static long eccdev_ioctl(struct file *, unsigned int, unsigned long); fp@1268: static int eccdev_mmap(struct file *, struct vm_area_struct *); fp@1258: fp@1272: /** This is the kernel version from which the .fault member of the fp@1272: * vm_operations_struct is usable. fp@1272: */ fp@1272: #define PAGE_FAULT_VERSION KERNEL_VERSION(2, 6, 23) fp@1272: fp@1272: #if LINUX_VERSION_CODE >= PAGE_FAULT_VERSION fp@1272: static int eccdev_vma_fault(struct vm_area_struct *, struct vm_fault *); fp@1272: #else fp@1258: static struct page *eccdev_vma_nopage( fp@1258: struct vm_area_struct *, unsigned long, int *); fp@1272: #endif fp@922: fp@922: /*****************************************************************************/ fp@922: fp@1268: /** File operation callbacks for the EtherCAT character device. fp@1268: */ fp@922: static struct file_operations eccdev_fops = { fp@935: .owner = THIS_MODULE, fp@935: .open = eccdev_open, fp@935: .release = eccdev_release, fp@1258: .unlocked_ioctl = eccdev_ioctl, fp@1258: .mmap = eccdev_mmap fp@1258: }; fp@1258: fp@1268: /** Callbacks for a virtual memory area retrieved with ecdevc_mmap(). fp@1268: */ fp@1258: struct vm_operations_struct eccdev_vm_ops = { fp@1272: #if LINUX_VERSION_CODE >= PAGE_FAULT_VERSION fp@1272: .fault = eccdev_vma_fault fp@1272: #else fp@1258: .nopage = eccdev_vma_nopage fp@1272: #endif fp@922: }; fp@922: fp@922: /*****************************************************************************/ fp@922: fp@1242: /** Private data structure for file handles. fp@1242: */ fp@1242: typedef struct { fp@1268: ec_cdev_t *cdev; /**< Character device. */ fp@1268: unsigned int requested; /**< Master wac requested via this file handle. */ fp@1268: uint8_t *process_data; /**< Total process data area. */ fp@1268: size_t process_data_size; /**< Size of the \a process_data. */ fp@1242: } ec_cdev_priv_t; fp@1242: fp@1242: /*****************************************************************************/ fp@1242: fp@922: /** Constructor. fp@922: * fp@922: * \return 0 in case of success, else < 0 fp@922: */ fp@922: int ec_cdev_init( fp@1507: ec_cdev_t *cdev, /**< EtherCAT master character device. */ fp@1507: ec_master_t *master, /**< Parent master. */ fp@1507: dev_t dev_num /**< Device number. */ fp@1507: ) fp@922: { fp@1313: int ret; fp@1313: fp@922: cdev->master = master; fp@922: fp@922: cdev_init(&cdev->cdev, &eccdev_fops); fp@922: cdev->cdev.owner = THIS_MODULE; fp@922: fp@1313: ret = cdev_add(&cdev->cdev, fp@1507: MKDEV(MAJOR(dev_num), master->index), 1); fp@1313: if (ret) { fp@1507: EC_ERR("Failed to add character device!\n"); fp@1313: } fp@1313: fp@1313: return ret; fp@922: } fp@922: fp@922: /*****************************************************************************/ fp@922: fp@922: /** Destructor. fp@922: */ fp@922: void ec_cdev_clear(ec_cdev_t *cdev /**< EtherCAT XML device */) fp@922: { fp@922: cdev_del(&cdev->cdev); fp@922: } fp@922: fp@1079: /*****************************************************************************/ fp@1079: fp@1108: /** Copies a string to an ioctl structure. fp@1108: */ fp@1108: void ec_cdev_strcpy( fp@1108: char *target, /**< Target. */ fp@1108: const char *source /**< Source. */ fp@1108: ) fp@1108: { fp@1108: if (source) { fp@1108: strncpy(target, source, EC_IOCTL_STRING_SIZE); fp@1108: target[EC_IOCTL_STRING_SIZE - 1] = 0; fp@1108: } else { fp@1108: target[0] = 0; fp@1108: } fp@1108: } fp@1108: fp@1108: /*****************************************************************************/ fp@1108: fp@1826: /** Get module information. fp@1826: */ fp@1826: int ec_cdev_ioctl_module( fp@1826: unsigned long arg /**< Userspace address to store the results. */ fp@1826: ) fp@1826: { fp@1826: ec_ioctl_module_t data; fp@1826: fp@1826: data.ioctl_version_magic = EC_IOCTL_VERSION_MAGIC; fp@1826: data.master_count = ec_master_count(); fp@1826: fp@1826: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1826: return -EFAULT; fp@1826: fp@1826: return 0; fp@1826: } fp@1826: fp@1826: /*****************************************************************************/ fp@1826: fp@1079: /** Get master information. fp@1079: */ fp@1079: int ec_cdev_ioctl_master( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< Userspace address to store the results. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_master_t data; fp@1851: unsigned int i; fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: data.slave_count = master->slave_count; fp@1079: data.config_count = ec_master_config_count(master); fp@1079: data.domain_count = ec_master_domain_count(master); fp@1516: #ifdef EC_EOE fp@1485: data.eoe_handler_count = ec_master_eoe_handler_count(master); fp@1516: #endif fp@1079: data.phase = (uint8_t) master->phase; fp@1530: data.active = (uint8_t) master->active; fp@1447: data.scan_busy = master->scan_busy; fp@1079: up(&master->master_sem); fp@1079: fp@1189: if (down_interruptible(&master->device_sem)) fp@1189: return -EINTR; fp@1415: fp@1162: if (master->main_device.dev) { fp@1162: memcpy(data.devices[0].address, fp@1162: master->main_device.dev->dev_addr, ETH_ALEN); fp@1162: } else { fp@1162: memcpy(data.devices[0].address, master->main_mac, ETH_ALEN); fp@1162: } fp@1079: data.devices[0].attached = master->main_device.dev ? 1 : 0; fp@1401: data.devices[0].link_state = master->main_device.link_state ? 1 : 0; fp@1079: data.devices[0].tx_count = master->main_device.tx_count; fp@1079: data.devices[0].rx_count = master->main_device.rx_count; fp@1851: for (i = 0; i < EC_RATE_COUNT; i++) { fp@1851: data.devices[0].tx_rates[i] = master->main_device.tx_rates[i]; fp@1851: data.devices[0].loss_rates[i] = master->main_device.loss_rates[i]; fp@1851: } fp@1162: fp@1162: if (master->backup_device.dev) { fp@1162: memcpy(data.devices[1].address, fp@1162: master->backup_device.dev->dev_addr, ETH_ALEN); fp@1162: } else { fp@1162: memcpy(data.devices[1].address, master->backup_mac, ETH_ALEN); fp@1162: } fp@1079: data.devices[1].attached = master->backup_device.dev ? 1 : 0; fp@1401: data.devices[1].link_state = master->backup_device.link_state ? 1 : 0; fp@1079: data.devices[1].tx_count = master->backup_device.tx_count; fp@1079: data.devices[1].rx_count = master->backup_device.rx_count; fp@1851: for (i = 0; i < EC_RATE_COUNT; i++) { fp@1851: data.devices[1].tx_rates[i] = master->backup_device.tx_rates[i]; fp@1851: data.devices[1].loss_rates[i] = master->backup_device.loss_rates[i]; fp@1851: } fp@1415: fp@1079: up(&master->device_sem); fp@1079: fp@1415: data.app_time = master->app_time; fp@1435: data.ref_clock = fp@1435: master->dc_ref_clock ? master->dc_ref_clock->ring_position : 0xffff; fp@1415: fp@1079: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1079: return -EFAULT; fp@1079: fp@1079: return 0; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1079: /** Get slave information. fp@1079: */ fp@1079: int ec_cdev_ioctl_slave( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< Userspace address to store the results. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_slave_t data; fp@1079: const ec_slave_t *slave; fp@1379: int i; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(slave = ec_master_find_slave_const( fp@1079: master, 0, data.position))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Slave %u does not exist!\n", data.position); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: data.vendor_id = slave->sii.vendor_id; fp@1079: data.product_code = slave->sii.product_code; fp@1079: data.revision_number = slave->sii.revision_number; fp@1079: data.serial_number = slave->sii.serial_number; fp@1079: data.alias = slave->sii.alias; fp@1337: data.boot_rx_mailbox_offset = slave->sii.boot_rx_mailbox_offset; fp@1337: data.boot_rx_mailbox_size = slave->sii.boot_rx_mailbox_size; fp@1337: data.boot_tx_mailbox_offset = slave->sii.boot_tx_mailbox_offset; fp@1337: data.boot_tx_mailbox_size = slave->sii.boot_tx_mailbox_size; fp@1337: data.std_rx_mailbox_offset = slave->sii.std_rx_mailbox_offset; fp@1337: data.std_rx_mailbox_size = slave->sii.std_rx_mailbox_size; fp@1337: data.std_tx_mailbox_offset = slave->sii.std_tx_mailbox_offset; fp@1337: data.std_tx_mailbox_size = slave->sii.std_tx_mailbox_size; fp@1079: data.mailbox_protocols = slave->sii.mailbox_protocols; fp@1079: data.has_general_category = slave->sii.has_general; fp@1079: data.coe_details = slave->sii.coe_details; fp@1079: data.general_flags = slave->sii.general_flags; fp@1079: data.current_on_ebus = slave->sii.current_on_ebus; fp@1379: for (i = 0; i < EC_MAX_PORTS; i++) { fp@1425: data.ports[i].desc = slave->ports[i].desc; fp@1425: data.ports[i].link.link_up = slave->ports[i].link.link_up; fp@1425: data.ports[i].link.loop_closed = slave->ports[i].link.loop_closed; fp@1831: data.ports[i].link.signal_detected = fp@1831: slave->ports[i].link.signal_detected; fp@1425: data.ports[i].receive_time = slave->ports[i].receive_time; fp@1425: if (slave->ports[i].next_slave) { fp@1831: data.ports[i].next_slave = fp@1831: slave->ports[i].next_slave->ring_position; fp@1421: } else { fp@1425: data.ports[i].next_slave = 0xffff; fp@1421: } fp@1425: data.ports[i].delay_to_next_dc = slave->ports[i].delay_to_next_dc; fp@1379: } fp@1379: data.fmmu_bit = slave->base_fmmu_bit_operation; fp@1379: data.dc_supported = slave->base_dc_supported; fp@1379: data.dc_range = slave->base_dc_range; fp@1419: data.has_dc_system_time = slave->has_dc_system_time; fp@1426: data.transmission_delay = slave->transmission_delay; fp@1148: data.al_state = slave->current_state; fp@1079: data.error_flag = slave->error_flag; fp@1079: fp@1079: data.sync_count = slave->sii.sync_count; fp@1079: data.sdo_count = ec_slave_sdo_count(slave); fp@1079: data.sii_nwords = slave->sii_nwords; fp@1109: ec_cdev_strcpy(data.group, slave->sii.group); fp@1109: ec_cdev_strcpy(data.image, slave->sii.image); fp@1109: ec_cdev_strcpy(data.order, slave->sii.order); fp@1108: ec_cdev_strcpy(data.name, slave->sii.name); fp@1079: fp@1079: up(&master->master_sem); fp@1079: fp@1079: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1079: return -EFAULT; fp@1079: fp@1079: return 0; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1079: /** Get slave sync manager information. fp@1079: */ fp@1079: int ec_cdev_ioctl_slave_sync( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< Userspace address to store the results. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_slave_sync_t data; fp@1079: const ec_slave_t *slave; fp@1079: const ec_sync_t *sync; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(slave = ec_master_find_slave_const( fp@1079: master, 0, data.slave_position))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Slave %u does not exist!\n", data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: if (data.sync_index >= slave->sii.sync_count) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Sync manager %u does not exist in slave %u!\n", fp@1079: data.sync_index, data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: sync = &slave->sii.syncs[data.sync_index]; fp@1079: fp@1079: data.physical_start_address = sync->physical_start_address; fp@1079: data.default_size = sync->default_length; fp@1079: data.control_register = sync->control_register; fp@1079: data.enable = sync->enable; fp@1079: data.pdo_count = ec_pdo_list_count(&sync->pdos); fp@1079: fp@1079: up(&master->master_sem); fp@1079: fp@1079: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1079: return -EFAULT; fp@1079: fp@1079: return 0; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1327: /** Get slave sync manager PDO information. fp@1079: */ fp@1079: int ec_cdev_ioctl_slave_sync_pdo( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< Userspace address to store the results. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_slave_sync_pdo_t data; fp@1079: const ec_slave_t *slave; fp@1079: const ec_sync_t *sync; fp@1079: const ec_pdo_t *pdo; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(slave = ec_master_find_slave_const( fp@1079: master, 0, data.slave_position))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Slave %u does not exist!\n", data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: if (data.sync_index >= slave->sii.sync_count) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Sync manager %u does not exist in slave %u!\n", fp@1079: data.sync_index, data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: sync = &slave->sii.syncs[data.sync_index]; fp@1079: if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( fp@1079: &sync->pdos, data.pdo_pos))) { fp@1079: up(&master->master_sem); fp@1327: EC_ERR("Sync manager %u does not contain a PDO with " fp@1079: "position %u in slave %u!\n", data.sync_index, fp@1079: data.pdo_pos, data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: data.index = pdo->index; fp@1079: data.entry_count = ec_pdo_entry_count(pdo); fp@1108: ec_cdev_strcpy(data.name, pdo->name); fp@1079: fp@1079: up(&master->master_sem); fp@1079: fp@1079: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1079: return -EFAULT; fp@1079: fp@1079: return 0; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1327: /** Get slave sync manager PDO entry information. fp@1079: */ fp@1079: int ec_cdev_ioctl_slave_sync_pdo_entry( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< Userspace address to store the results. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_slave_sync_pdo_entry_t data; fp@1079: const ec_slave_t *slave; fp@1079: const ec_sync_t *sync; fp@1079: const ec_pdo_t *pdo; fp@1079: const ec_pdo_entry_t *entry; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(slave = ec_master_find_slave_const( fp@1079: master, 0, data.slave_position))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Slave %u does not exist!\n", data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: if (data.sync_index >= slave->sii.sync_count) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Sync manager %u does not exist in slave %u!\n", fp@1079: data.sync_index, data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: sync = &slave->sii.syncs[data.sync_index]; fp@1079: if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( fp@1079: &sync->pdos, data.pdo_pos))) { fp@1079: up(&master->master_sem); fp@1327: EC_ERR("Sync manager %u does not contain a PDO with " fp@1079: "position %u in slave %u!\n", data.sync_index, fp@1079: data.pdo_pos, data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: if (!(entry = ec_pdo_find_entry_by_pos_const( fp@1079: pdo, data.entry_pos))) { fp@1079: up(&master->master_sem); fp@1327: EC_ERR("PDO 0x%04X does not contain an entry with " fp@1079: "position %u in slave %u!\n", data.pdo_pos, fp@1079: data.entry_pos, data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: data.index = entry->index; fp@1079: data.subindex = entry->subindex; fp@1079: data.bit_length = entry->bit_length; fp@1108: ec_cdev_strcpy(data.name, entry->name); fp@1079: fp@1079: up(&master->master_sem); fp@1079: fp@1079: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1079: return -EFAULT; fp@1079: fp@1079: return 0; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1079: /** Get domain information. fp@1079: */ fp@1079: int ec_cdev_ioctl_domain( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< Userspace address to store the results. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_domain_t data; fp@1079: const ec_domain_t *domain; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(domain = ec_master_find_domain_const(master, data.index))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Domain %u does not exist!\n", data.index); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: data.data_size = domain->data_size; fp@1079: data.logical_base_address = domain->logical_base_address; fp@1079: data.working_counter = domain->working_counter; fp@1079: data.expected_working_counter = domain->expected_working_counter; fp@1079: data.fmmu_count = ec_domain_fmmu_count(domain); fp@1079: fp@1079: up(&master->master_sem); fp@1079: fp@1079: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1079: return -EFAULT; fp@1079: fp@1079: return 0; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1079: /** Get domain FMMU information. fp@1079: */ fp@1079: int ec_cdev_ioctl_domain_fmmu( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< Userspace address to store the results. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_domain_fmmu_t data; fp@1079: const ec_domain_t *domain; fp@1079: const ec_fmmu_config_t *fmmu; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(domain = ec_master_find_domain_const(master, data.domain_index))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Domain %u does not exist!\n", data.domain_index); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: if (!(fmmu = ec_domain_find_fmmu(domain, data.fmmu_index))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Domain %u has less than %u fmmu configurations.\n", fp@1079: data.domain_index, data.fmmu_index + 1); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: data.slave_config_alias = fmmu->sc->alias; fp@1079: data.slave_config_position = fmmu->sc->position; fp@1079: data.sync_index = fmmu->sync_index; fp@1079: data.dir = fmmu->dir; fp@1079: data.logical_address = fmmu->logical_start_address; fp@1079: data.data_size = fmmu->data_size; fp@1079: fp@1079: up(&master->master_sem); fp@1079: fp@1079: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1079: return -EFAULT; fp@1079: fp@1079: return 0; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1079: /** Get domain data. fp@1079: */ fp@1079: int ec_cdev_ioctl_domain_data( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< Userspace address to store the results. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_domain_data_t data; fp@1079: const ec_domain_t *domain; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(domain = ec_master_find_domain_const(master, data.domain_index))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Domain %u does not exist!\n", data.domain_index); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: if (domain->data_size != data.data_size) { fp@1079: up(&master->master_sem); fp@1543: EC_ERR("Data size mismatch %u/%zu!\n", fp@1079: data.data_size, domain->data_size); fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1079: if (copy_to_user((void __user *) data.target, domain->data, fp@1223: domain->data_size)) { fp@1223: up(&master->master_sem); fp@1223: return -EFAULT; fp@1223: } fp@1079: fp@1079: up(&master->master_sem); fp@1079: return 0; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1079: /** Set master debug level. fp@1079: */ fp@1079: int ec_cdev_ioctl_master_debug( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< ioctl() argument. */ fp@1079: ) fp@1079: { fp@1313: return ec_master_debug_level(master, (unsigned int) arg); fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1079: /** Set slave state. fp@1079: */ fp@1079: int ec_cdev_ioctl_slave_state( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< ioctl() argument. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_slave_state_t data; fp@1079: ec_slave_t *slave; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(slave = ec_master_find_slave( fp@1079: master, 0, data.slave_position))) { fp@1196: up(&master->master_sem); fp@1079: EC_ERR("Slave %u does not exist!\n", data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1150: ec_slave_request_state(slave, data.al_state); fp@1079: fp@1079: up(&master->master_sem); fp@1079: return 0; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1327: /** Get slave SDO information. fp@1079: */ fp@1079: int ec_cdev_ioctl_slave_sdo( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< ioctl() argument. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_slave_sdo_t data; fp@1079: const ec_slave_t *slave; fp@1079: const ec_sdo_t *sdo; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(slave = ec_master_find_slave_const( fp@1079: master, 0, data.slave_position))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Slave %u does not exist!\n", data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: if (!(sdo = ec_slave_get_sdo_by_pos_const( fp@1079: slave, data.sdo_position))) { fp@1079: up(&master->master_sem); fp@1327: EC_ERR("SDO %u does not exist in slave %u!\n", fp@1079: data.sdo_position, data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: data.sdo_index = sdo->index; fp@1079: data.max_subindex = sdo->max_subindex; fp@1108: ec_cdev_strcpy(data.name, sdo->name); fp@1079: fp@1079: up(&master->master_sem); fp@1079: fp@1079: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1079: return -EFAULT; fp@1079: fp@1079: return 0; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1327: /** Get slave SDO entry information. fp@1079: */ fp@1079: int ec_cdev_ioctl_slave_sdo_entry( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< ioctl() argument. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_slave_sdo_entry_t data; fp@1079: const ec_slave_t *slave; fp@1079: const ec_sdo_t *sdo; fp@1079: const ec_sdo_entry_t *entry; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(slave = ec_master_find_slave_const( fp@1079: master, 0, data.slave_position))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Slave %u does not exist!\n", data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: if (data.sdo_spec <= 0) { fp@1079: if (!(sdo = ec_slave_get_sdo_by_pos_const( fp@1079: slave, -data.sdo_spec))) { fp@1079: up(&master->master_sem); fp@1327: EC_ERR("SDO %u does not exist in slave %u!\n", fp@1079: -data.sdo_spec, data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: } else { fp@1079: if (!(sdo = ec_slave_get_sdo_const( fp@1079: slave, data.sdo_spec))) { fp@1079: up(&master->master_sem); fp@1327: EC_ERR("SDO 0x%04X does not exist in slave %u!\n", fp@1079: data.sdo_spec, data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: } fp@1079: fp@1079: if (!(entry = ec_sdo_get_entry_const( fp@1079: sdo, data.sdo_entry_subindex))) { fp@1079: up(&master->master_sem); fp@1327: EC_ERR("SDO entry 0x%04X:%02X does not exist " fp@1079: "in slave %u!\n", sdo->index, fp@1079: data.sdo_entry_subindex, data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: data.data_type = entry->data_type; fp@1079: data.bit_length = entry->bit_length; fp@1382: data.read_access[EC_SDO_ENTRY_ACCESS_PREOP] = fp@1382: entry->read_access[EC_SDO_ENTRY_ACCESS_PREOP]; fp@1382: data.read_access[EC_SDO_ENTRY_ACCESS_SAFEOP] = fp@1382: entry->read_access[EC_SDO_ENTRY_ACCESS_SAFEOP]; fp@1382: data.read_access[EC_SDO_ENTRY_ACCESS_OP] = fp@1382: entry->read_access[EC_SDO_ENTRY_ACCESS_OP]; fp@1382: data.write_access[EC_SDO_ENTRY_ACCESS_PREOP] = fp@1382: entry->write_access[EC_SDO_ENTRY_ACCESS_PREOP]; fp@1382: data.write_access[EC_SDO_ENTRY_ACCESS_SAFEOP] = fp@1382: entry->write_access[EC_SDO_ENTRY_ACCESS_SAFEOP]; fp@1382: data.write_access[EC_SDO_ENTRY_ACCESS_OP] = fp@1382: entry->write_access[EC_SDO_ENTRY_ACCESS_OP]; fp@1108: ec_cdev_strcpy(data.description, entry->description); fp@1079: fp@1079: up(&master->master_sem); fp@1079: fp@1079: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1079: return -EFAULT; fp@1079: fp@1079: return 0; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1327: /** Upload SDO. fp@1079: */ fp@1079: int ec_cdev_ioctl_slave_sdo_upload( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< ioctl() argument. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_slave_sdo_upload_t data; fp@1079: ec_master_sdo_request_t request; fp@1079: int retval; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1079: ec_sdo_request_init(&request.req); fp@1079: ec_sdo_request_address(&request.req, fp@1079: data.sdo_index, data.sdo_entry_subindex); fp@1079: ecrt_sdo_request_read(&request.req); fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(request.slave = ec_master_find_slave( fp@1079: master, 0, data.slave_position))) { fp@1079: up(&master->master_sem); fp@1079: ec_sdo_request_clear(&request.req); fp@1079: EC_ERR("Slave %u does not exist!\n", data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: martin@1583: if (master->debug_level) fp@1831: EC_DBG("Schedule SDO upload request for slave %u\n", fp@1831: request.slave->ring_position); fp@1079: // schedule request. martin@1596: list_add_tail(&request.list, &request.slave->slave_sdo_requests); fp@1079: fp@1079: up(&master->master_sem); fp@1079: fp@1079: // wait for processing through FSM martin@1596: if (wait_event_interruptible(request.slave->sdo_queue, fp@1209: request.req.state != EC_INT_REQUEST_QUEUED)) { fp@1079: // interrupted by signal fp@1079: down(&master->master_sem); fp@1209: if (request.req.state == EC_INT_REQUEST_QUEUED) { martin@1582: list_del(&request.list); fp@1079: up(&master->master_sem); fp@1079: ec_sdo_request_clear(&request.req); fp@1079: return -EINTR; fp@1079: } fp@1079: // request already processing: interrupt not possible. fp@1079: up(&master->master_sem); fp@1079: } fp@1079: fp@1079: // wait until master FSM has finished processing fp@1831: wait_event(request.slave->sdo_queue, fp@1831: request.req.state != EC_INT_REQUEST_BUSY); fp@1079: martin@1583: if (master->debug_level) fp@1831: EC_DBG("Scheduled SDO upload request for slave %u done\n", fp@1831: request.slave->ring_position); martin@1583: fp@1079: data.abort_code = request.req.abort_code; fp@1079: fp@1209: if (request.req.state != EC_INT_REQUEST_SUCCESS) { fp@1079: data.data_size = 0; fp@1079: retval = -EIO; fp@1079: } else { fp@1079: if (request.req.data_size > data.target_size) { fp@1079: EC_ERR("Buffer too small.\n"); fp@1079: ec_sdo_request_clear(&request.req); fp@1079: return -EOVERFLOW; fp@1079: } fp@1079: data.data_size = request.req.data_size; fp@1079: fp@1079: if (copy_to_user((void __user *) data.target, fp@1079: request.req.data, data.data_size)) { fp@1079: ec_sdo_request_clear(&request.req); fp@1079: return -EFAULT; fp@1079: } fp@1079: retval = 0; fp@1079: } fp@1079: fp@1079: if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { fp@1079: retval = -EFAULT; fp@1079: } fp@1079: fp@1079: ec_sdo_request_clear(&request.req); fp@1079: return retval; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1327: /** Download SDO. fp@1079: */ fp@1079: int ec_cdev_ioctl_slave_sdo_download( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< ioctl() argument. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_slave_sdo_download_t data; fp@1079: ec_master_sdo_request_t request; fp@1079: int retval; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1079: // copy data to download fp@1079: if (!data.data_size) { fp@1079: EC_ERR("Zero data size!\n"); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: ec_sdo_request_init(&request.req); fp@1079: ec_sdo_request_address(&request.req, fp@1079: data.sdo_index, data.sdo_entry_subindex); fp@1079: if (ec_sdo_request_alloc(&request.req, data.data_size)) { fp@1079: ec_sdo_request_clear(&request.req); fp@1079: return -ENOMEM; fp@1079: } fp@1079: if (copy_from_user(request.req.data, fp@1079: (void __user *) data.data, data.data_size)) { fp@1079: ec_sdo_request_clear(&request.req); fp@1079: return -EFAULT; fp@1079: } fp@1079: request.req.data_size = data.data_size; fp@1079: ecrt_sdo_request_write(&request.req); fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(request.slave = ec_master_find_slave( fp@1079: master, 0, data.slave_position))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Slave %u does not exist!\n", data.slave_position); fp@1079: ec_sdo_request_clear(&request.req); fp@1079: return -EINVAL; fp@1079: } fp@1079: martin@1583: if (master->debug_level) fp@1831: EC_DBG("Schedule SDO download request for slave %u\n", fp@1831: request.slave->ring_position); fp@1079: // schedule request. martin@1596: list_add_tail(&request.list, &request.slave->slave_sdo_requests); fp@1079: fp@1079: up(&master->master_sem); fp@1079: fp@1079: // wait for processing through FSM martin@1596: if (wait_event_interruptible(request.slave->sdo_queue, fp@1209: request.req.state != EC_INT_REQUEST_QUEUED)) { fp@1079: // interrupted by signal fp@1079: down(&master->master_sem); fp@1209: if (request.req.state == EC_INT_REQUEST_QUEUED) { martin@1582: list_del(&request.list); fp@1079: up(&master->master_sem); fp@1079: ec_sdo_request_clear(&request.req); fp@1079: return -EINTR; fp@1079: } fp@1079: // request already processing: interrupt not possible. fp@1079: up(&master->master_sem); fp@1079: } fp@1079: fp@1079: // wait until master FSM has finished processing fp@1831: wait_event(request.slave->sdo_queue, fp@1831: request.req.state != EC_INT_REQUEST_BUSY); fp@1079: martin@1583: if (master->debug_level) fp@1831: EC_DBG("Scheduled SDO download request for slave %u done\n", fp@1831: request.slave->ring_position); martin@1583: fp@1079: data.abort_code = request.req.abort_code; fp@1079: fp@1209: retval = request.req.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; fp@1079: fp@1079: if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { fp@1079: retval = -EFAULT; fp@1079: } fp@1079: fp@1079: ec_sdo_request_clear(&request.req); fp@1079: return retval; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1079: /** Read a slave's SII. fp@1079: */ fp@1079: int ec_cdev_ioctl_slave_sii_read( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< ioctl() argument. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_slave_sii_t data; fp@1079: const ec_slave_t *slave; fp@1079: int retval; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(slave = ec_master_find_slave_const( fp@1079: master, 0, data.slave_position))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Slave %u does not exist!\n", data.slave_position); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: if (!data.nwords fp@1079: || data.offset + data.nwords > slave->sii_nwords) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Invalid SII read offset/size %u/%u for slave " fp@1543: "SII size %zu!\n", data.offset, fp@1079: data.nwords, slave->sii_nwords); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: if (copy_to_user((void __user *) data.words, fp@1079: slave->sii_words + data.offset, data.nwords * 2)) fp@1079: retval = -EFAULT; fp@1079: else fp@1079: retval = 0; fp@1079: fp@1079: up(&master->master_sem); fp@1079: return retval; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1079: /** Write a slave's SII. fp@1079: */ fp@1079: int ec_cdev_ioctl_slave_sii_write( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< ioctl() argument. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_slave_sii_t data; fp@1079: ec_slave_t *slave; fp@1079: unsigned int byte_size; fp@1079: uint16_t *words; fp@1079: ec_sii_write_request_t request; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1079: if (!data.nwords) fp@1079: return 0; fp@1079: fp@1079: byte_size = sizeof(uint16_t) * data.nwords; fp@1079: if (!(words = kmalloc(byte_size, GFP_KERNEL))) { fp@1079: EC_ERR("Failed to allocate %u bytes for SII contents.\n", fp@1079: byte_size); fp@1079: return -ENOMEM; fp@1079: } fp@1079: fp@1079: if (copy_from_user(words, fp@1079: (void __user *) data.words, byte_size)) { fp@1079: kfree(words); fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(slave = ec_master_find_slave( fp@1079: master, 0, data.slave_position))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Slave %u does not exist!\n", data.slave_position); fp@1079: kfree(words); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: // init SII write request fp@1079: INIT_LIST_HEAD(&request.list); fp@1079: request.slave = slave; fp@1079: request.words = words; fp@1079: request.offset = data.offset; fp@1079: request.nwords = data.nwords; fp@1209: request.state = EC_INT_REQUEST_QUEUED; fp@1079: fp@1079: // schedule SII write request. fp@1079: list_add_tail(&request.list, &master->sii_requests); fp@1079: fp@1079: up(&master->master_sem); fp@1079: fp@1079: // wait for processing through FSM fp@1079: if (wait_event_interruptible(master->sii_queue, fp@1209: request.state != EC_INT_REQUEST_QUEUED)) { fp@1079: // interrupted by signal fp@1079: down(&master->master_sem); fp@1209: if (request.state == EC_INT_REQUEST_QUEUED) { fp@1079: // abort request fp@1079: list_del(&request.list); fp@1079: up(&master->master_sem); fp@1079: kfree(words); fp@1079: return -EINTR; fp@1079: } fp@1079: up(&master->master_sem); fp@1079: } fp@1079: fp@1079: // wait until master FSM has finished processing fp@1209: wait_event(master->sii_queue, request.state != EC_INT_REQUEST_BUSY); fp@1079: fp@1079: kfree(words); fp@1079: fp@1209: return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1388: /** Read a slave's registers. fp@1388: */ fp@1388: int ec_cdev_ioctl_slave_reg_read( fp@1200: ec_master_t *master, /**< EtherCAT master. */ fp@1200: unsigned long arg /**< ioctl() argument. */ fp@1200: ) fp@1200: { fp@1388: ec_ioctl_slave_reg_t data; fp@1200: ec_slave_t *slave; fp@1200: uint8_t *contents; fp@1388: ec_reg_request_t request; fp@1200: fp@1200: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1200: return -EFAULT; fp@1200: } fp@1200: fp@1200: if (!data.length) fp@1200: return 0; fp@1200: fp@1200: if (!(contents = kmalloc(data.length, GFP_KERNEL))) { fp@1831: EC_ERR("Failed to allocate %u bytes for register data.\n", fp@1831: data.length); fp@1200: return -ENOMEM; fp@1200: } fp@1200: fp@1200: if (down_interruptible(&master->master_sem)) fp@1200: return -EINTR; fp@1200: fp@1200: if (!(slave = ec_master_find_slave( fp@1200: master, 0, data.slave_position))) { fp@1200: up(&master->master_sem); fp@1200: EC_ERR("Slave %u does not exist!\n", data.slave_position); fp@1200: return -EINVAL; fp@1200: } fp@1200: fp@1388: // init register request fp@1200: INIT_LIST_HEAD(&request.list); fp@1200: request.slave = slave; fp@1200: request.dir = EC_DIR_INPUT; fp@1200: request.data = contents; fp@1200: request.offset = data.offset; fp@1200: request.length = data.length; fp@1209: request.state = EC_INT_REQUEST_QUEUED; fp@1200: fp@1200: // schedule request. fp@1388: list_add_tail(&request.list, &master->reg_requests); fp@1200: fp@1200: up(&master->master_sem); fp@1200: fp@1200: // wait for processing through FSM fp@1388: if (wait_event_interruptible(master->reg_queue, fp@1209: request.state != EC_INT_REQUEST_QUEUED)) { fp@1200: // interrupted by signal fp@1200: down(&master->master_sem); fp@1209: if (request.state == EC_INT_REQUEST_QUEUED) { fp@1200: // abort request fp@1200: list_del(&request.list); fp@1200: up(&master->master_sem); fp@1200: kfree(contents); fp@1200: return -EINTR; fp@1200: } fp@1200: up(&master->master_sem); fp@1200: } fp@1200: fp@1200: // wait until master FSM has finished processing fp@1388: wait_event(master->reg_queue, request.state != EC_INT_REQUEST_BUSY); fp@1209: fp@1209: if (request.state == EC_INT_REQUEST_SUCCESS) { fp@1200: if (copy_to_user((void __user *) data.data, contents, data.length)) fp@1200: return -EFAULT; fp@1200: } fp@1200: kfree(contents); fp@1200: fp@1209: return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; fp@1200: } fp@1200: fp@1200: /*****************************************************************************/ fp@1200: fp@1388: /** Write a slave's registers. fp@1388: */ fp@1388: int ec_cdev_ioctl_slave_reg_write( fp@1200: ec_master_t *master, /**< EtherCAT master. */ fp@1200: unsigned long arg /**< ioctl() argument. */ fp@1200: ) fp@1200: { fp@1388: ec_ioctl_slave_reg_t data; fp@1200: ec_slave_t *slave; fp@1200: uint8_t *contents; fp@1388: ec_reg_request_t request; fp@1200: fp@1200: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1200: return -EFAULT; fp@1200: } fp@1200: fp@1200: if (!data.length) fp@1200: return 0; fp@1200: fp@1200: if (!(contents = kmalloc(data.length, GFP_KERNEL))) { fp@1831: EC_ERR("Failed to allocate %u bytes for register data.\n", fp@1831: data.length); fp@1200: return -ENOMEM; fp@1200: } fp@1200: fp@1200: if (copy_from_user(contents, (void __user *) data.data, data.length)) { fp@1200: kfree(contents); fp@1200: return -EFAULT; fp@1200: } fp@1200: fp@1200: if (down_interruptible(&master->master_sem)) fp@1200: return -EINTR; fp@1200: fp@1200: if (!(slave = ec_master_find_slave( fp@1200: master, 0, data.slave_position))) { fp@1200: up(&master->master_sem); fp@1200: EC_ERR("Slave %u does not exist!\n", data.slave_position); fp@1200: kfree(contents); fp@1200: return -EINVAL; fp@1200: } fp@1200: fp@1388: // init register request fp@1200: INIT_LIST_HEAD(&request.list); fp@1200: request.slave = slave; fp@1200: request.dir = EC_DIR_OUTPUT; fp@1200: request.data = contents; fp@1200: request.offset = data.offset; fp@1200: request.length = data.length; fp@1209: request.state = EC_INT_REQUEST_QUEUED; fp@1200: fp@1200: // schedule request. fp@1388: list_add_tail(&request.list, &master->reg_requests); fp@1200: fp@1200: up(&master->master_sem); fp@1200: fp@1200: // wait for processing through FSM fp@1388: if (wait_event_interruptible(master->reg_queue, fp@1209: request.state != EC_INT_REQUEST_QUEUED)) { fp@1200: // interrupted by signal fp@1200: down(&master->master_sem); fp@1209: if (request.state == EC_INT_REQUEST_QUEUED) { fp@1200: // abort request fp@1200: list_del(&request.list); fp@1200: up(&master->master_sem); fp@1200: kfree(contents); fp@1200: return -EINTR; fp@1200: } fp@1200: up(&master->master_sem); fp@1200: } fp@1200: fp@1200: // wait until master FSM has finished processing fp@1388: wait_event(master->reg_queue, request.state != EC_INT_REQUEST_BUSY); fp@1200: fp@1200: kfree(contents); fp@1200: fp@1209: return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; fp@1200: } fp@1200: fp@1200: /*****************************************************************************/ fp@1200: fp@1079: /** Get slave configuration information. fp@1079: */ fp@1079: int ec_cdev_ioctl_config( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< ioctl() argument. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_config_t data; fp@1079: const ec_slave_config_t *sc; fp@1079: uint8_t i; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(sc = ec_master_get_config_const( fp@1079: master, data.config_index))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Slave config %u does not exist!\n", fp@1079: data.config_index); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: data.alias = sc->alias; fp@1079: data.position = sc->position; fp@1079: data.vendor_id = sc->vendor_id; fp@1079: data.product_code = sc->product_code; fp@1082: for (i = 0; i < EC_MAX_SYNC_MANAGERS; i++) { fp@1079: data.syncs[i].dir = sc->sync_configs[i].dir; fp@1518: data.syncs[i].watchdog_mode = sc->sync_configs[i].watchdog_mode; fp@1079: data.syncs[i].pdo_count = fp@1079: ec_pdo_list_count(&sc->sync_configs[i].pdos); fp@1079: } fp@1518: data.watchdog_divider = sc->watchdog_divider; fp@1518: data.watchdog_intervals = sc->watchdog_intervals; fp@1079: data.sdo_count = ec_slave_config_sdo_count(sc); fp@1147: data.slave_position = sc->slave ? sc->slave->ring_position : -1; fp@1455: data.dc_assign_activate = sc->dc_assign_activate; fp@1455: for (i = 0; i < EC_SYNC_SIGNAL_COUNT; i++) { fp@1455: data.dc_sync[i] = sc->dc_sync[i]; fp@1455: } fp@1079: fp@1079: up(&master->master_sem); fp@1079: fp@1079: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1079: return -EFAULT; fp@1079: fp@1079: return 0; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1327: /** Get slave configuration PDO information. fp@1079: */ fp@1079: int ec_cdev_ioctl_config_pdo( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< ioctl() argument. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_config_pdo_t data; fp@1079: const ec_slave_config_t *sc; fp@1079: const ec_pdo_t *pdo; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1082: if (data.sync_index >= EC_MAX_SYNC_MANAGERS) { fp@1079: EC_ERR("Invalid sync manager index %u!\n", fp@1079: data.sync_index); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(sc = ec_master_get_config_const( fp@1079: master, data.config_index))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Slave config %u does not exist!\n", fp@1079: data.config_index); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( fp@1079: &sc->sync_configs[data.sync_index].pdos, fp@1079: data.pdo_pos))) { fp@1079: up(&master->master_sem); fp@1327: EC_ERR("Invalid PDO position!\n"); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: data.index = pdo->index; fp@1079: data.entry_count = ec_pdo_entry_count(pdo); fp@1108: ec_cdev_strcpy(data.name, pdo->name); fp@1079: fp@1079: up(&master->master_sem); fp@1079: fp@1079: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1079: return -EFAULT; fp@1079: fp@1079: return 0; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1327: /** Get slave configuration PDO entry information. fp@1079: */ fp@1079: int ec_cdev_ioctl_config_pdo_entry( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< ioctl() argument. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_config_pdo_entry_t data; fp@1079: const ec_slave_config_t *sc; fp@1079: const ec_pdo_t *pdo; fp@1079: const ec_pdo_entry_t *entry; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1082: if (data.sync_index >= EC_MAX_SYNC_MANAGERS) { fp@1079: EC_ERR("Invalid sync manager index %u!\n", fp@1079: data.sync_index); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(sc = ec_master_get_config_const( fp@1079: master, data.config_index))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Slave config %u does not exist!\n", fp@1079: data.config_index); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( fp@1079: &sc->sync_configs[data.sync_index].pdos, fp@1079: data.pdo_pos))) { fp@1079: up(&master->master_sem); fp@1327: EC_ERR("Invalid PDO position!\n"); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: if (!(entry = ec_pdo_find_entry_by_pos_const( fp@1079: pdo, data.entry_pos))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Entry not found!\n"); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: data.index = entry->index; fp@1079: data.subindex = entry->subindex; fp@1079: data.bit_length = entry->bit_length; fp@1108: ec_cdev_strcpy(data.name, entry->name); fp@1079: fp@1079: up(&master->master_sem); fp@1079: fp@1079: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1079: return -EFAULT; fp@1079: fp@1079: return 0; fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1079: fp@1327: /** Get slave configuration SDO information. fp@1079: */ fp@1079: int ec_cdev_ioctl_config_sdo( fp@1079: ec_master_t *master, /**< EtherCAT master. */ fp@1079: unsigned long arg /**< ioctl() argument. */ fp@1079: ) fp@1079: { fp@1079: ec_ioctl_config_sdo_t data; fp@1079: const ec_slave_config_t *sc; fp@1079: const ec_sdo_request_t *req; fp@1079: fp@1079: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1079: return -EFAULT; fp@1079: } fp@1079: fp@1189: if (down_interruptible(&master->master_sem)) fp@1189: return -EINTR; fp@1079: fp@1079: if (!(sc = ec_master_get_config_const( fp@1079: master, data.config_index))) { fp@1079: up(&master->master_sem); fp@1079: EC_ERR("Slave config %u does not exist!\n", fp@1079: data.config_index); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: if (!(req = ec_slave_config_get_sdo_by_pos_const( fp@1079: sc, data.sdo_pos))) { fp@1079: up(&master->master_sem); fp@1327: EC_ERR("Invalid SDO position!\n"); fp@1079: return -EINVAL; fp@1079: } fp@1079: fp@1079: data.index = req->index; fp@1079: data.subindex = req->subindex; fp@1079: data.size = req->data_size; fp@1526: memcpy(&data.data, req->data, fp@1526: min((u32) data.size, (u32) EC_MAX_SDO_DATA_SIZE)); fp@1079: fp@1079: up(&master->master_sem); fp@1079: fp@1079: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1079: return -EFAULT; fp@1079: fp@1079: return 0; fp@1079: } fp@1079: fp@1242: /*****************************************************************************/ fp@1242: fp@1516: #ifdef EC_EOE fp@1516: fp@1485: /** Get EoE handler information. fp@1485: */ fp@1485: int ec_cdev_ioctl_eoe_handler( fp@1485: ec_master_t *master, /**< EtherCAT master. */ fp@1485: unsigned long arg /**< ioctl() argument. */ fp@1485: ) fp@1485: { fp@1485: ec_ioctl_eoe_handler_t data; fp@1507: const ec_eoe_t *eoe; fp@1485: fp@1485: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1485: return -EFAULT; fp@1485: } fp@1485: fp@1485: if (down_interruptible(&master->master_sem)) fp@1485: return -EINTR; fp@1485: fp@1485: if (!(eoe = ec_master_get_eoe_handler_const(master, data.eoe_index))) { fp@1485: up(&master->master_sem); fp@1485: EC_ERR("EoE handler %u does not exist!\n", data.eoe_index); fp@1485: return -EINVAL; fp@1485: } fp@1485: fp@1507: if (eoe->slave) { fp@1507: data.slave_position = eoe->slave->ring_position; fp@1507: } else { fp@1507: data.slave_position = 0xffff; fp@1507: } fp@1507: snprintf(data.name, EC_DATAGRAM_NAME_SIZE, eoe->dev->name); fp@1485: data.open = eoe->opened; fp@1485: data.rx_bytes = eoe->stats.tx_bytes; fp@1485: data.rx_rate = eoe->tx_rate; fp@1485: data.tx_bytes = eoe->stats.rx_bytes; fp@1485: data.tx_rate = eoe->tx_rate; fp@1485: data.tx_queued_frames = eoe->tx_queued_frames; fp@1485: data.tx_queue_size = eoe->tx_queue_size; fp@1485: fp@1485: up(&master->master_sem); fp@1485: fp@1485: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1485: return -EFAULT; fp@1485: fp@1485: return 0; fp@1485: } fp@1485: fp@1516: #endif fp@1516: fp@1485: /*****************************************************************************/ fp@1485: fp@1242: /** Request the master from userspace. fp@1242: */ fp@1242: int ec_cdev_ioctl_request( fp@1242: ec_master_t *master, /**< EtherCAT master. */ fp@1242: unsigned long arg, /**< ioctl() argument. */ fp@1242: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1242: ) fp@1242: { fp@1507: ec_master_t *m; fp@1242: int ret = 0; fp@1242: fp@1312: m = ecrt_request_master_err(master->index); fp@1244: if (IS_ERR(m)) { fp@1244: ret = PTR_ERR(m); fp@1242: } else { fp@1242: priv->requested = 1; fp@1242: } fp@1242: fp@1242: return ret; fp@1242: } fp@1242: fp@1244: /*****************************************************************************/ fp@1244: fp@1244: /** Create a domain. fp@1244: */ fp@1244: int ec_cdev_ioctl_create_domain( fp@1244: ec_master_t *master, /**< EtherCAT master. */ fp@1244: unsigned long arg, /**< ioctl() argument. */ fp@1244: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1244: ) fp@1244: { fp@1244: ec_domain_t *domain; fp@1244: fp@1507: if (unlikely(!priv->requested)) fp@1507: return -EPERM; fp@1244: fp@1312: domain = ecrt_master_create_domain_err(master); fp@1312: if (IS_ERR(domain)) fp@1312: return PTR_ERR(domain); fp@1244: fp@1244: return domain->index; fp@1244: } fp@1244: fp@1246: /*****************************************************************************/ fp@1246: fp@1246: /** Create a slave configuration. fp@1246: */ fp@1246: int ec_cdev_ioctl_create_slave_config( fp@1246: ec_master_t *master, /**< EtherCAT master. */ fp@1246: unsigned long arg, /**< ioctl() argument. */ fp@1246: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1246: ) fp@1246: { fp@1246: ec_ioctl_config_t data; fp@1246: ec_slave_config_t *sc, *entry; fp@1246: fp@1507: if (unlikely(!priv->requested)) fp@1507: return -EPERM; fp@1246: fp@1246: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1246: return -EFAULT; fp@1246: } fp@1246: fp@1312: sc = ecrt_master_slave_config_err(master, data.alias, data.position, fp@1246: data.vendor_id, data.product_code); fp@1312: if (IS_ERR(sc)) fp@1312: return PTR_ERR(sc); fp@1246: fp@1246: data.config_index = 0; fp@1246: fp@1246: if (down_interruptible(&master->master_sem)) fp@1246: return -EINTR; fp@1246: fp@1246: list_for_each_entry(entry, &master->configs, list) { fp@1246: if (entry == sc) fp@1246: break; fp@1246: data.config_index++; fp@1246: } fp@1246: fp@1246: up(&master->master_sem); fp@1246: fp@1246: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1246: return -EFAULT; fp@1246: fp@1246: return 0; fp@1246: } fp@1246: fp@1247: /*****************************************************************************/ fp@1247: fp@1247: /** Activates the master. fp@1247: */ fp@1247: int ec_cdev_ioctl_activate( fp@1247: ec_master_t *master, /**< EtherCAT master. */ fp@1247: unsigned long arg, /**< ioctl() argument. */ fp@1247: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1247: ) fp@1247: { fp@1258: ec_domain_t *domain; fp@1258: off_t offset; fp@1313: int ret; fp@1258: fp@1507: if (unlikely(!priv->requested)) fp@1507: return -EPERM; fp@1247: fp@1258: /* Get the sum of the domains' process data sizes. */ fp@1258: fp@1258: priv->process_data_size = 0; fp@1258: fp@1258: if (down_interruptible(&master->master_sem)) fp@1258: return -EINTR; fp@1258: fp@1258: list_for_each_entry(domain, &master->domains, list) { fp@1258: priv->process_data_size += ecrt_domain_size(domain); fp@1258: } fp@1258: fp@1258: up(&master->master_sem); fp@1258: fp@1258: if (priv->process_data_size) { fp@1258: priv->process_data = vmalloc(priv->process_data_size); fp@1258: if (!priv->process_data) { fp@1258: priv->process_data_size = 0; fp@1258: return -ENOMEM; fp@1258: } fp@1258: fp@1258: /* Set the memory as external process data memory for the domains. */ fp@1258: fp@1258: offset = 0; fp@1258: list_for_each_entry(domain, &master->domains, list) { fp@1258: ecrt_domain_external_memory(domain, priv->process_data + offset); fp@1258: offset += ecrt_domain_size(domain); fp@1258: } fp@1258: } fp@1258: fp@1500: ecrt_master_callbacks(master, ec_master_internal_send_cb, fp@1513: ec_master_internal_receive_cb, master); fp@1500: fp@1313: ret = ecrt_master_activate(master); fp@1313: if (ret < 0) fp@1313: return ret; fp@1247: fp@1258: if (copy_to_user((void __user *) arg, fp@1258: &priv->process_data_size, sizeof(size_t))) fp@1258: return -EFAULT; fp@1258: fp@1247: return 0; fp@1247: } fp@1247: fp@1247: /*****************************************************************************/ fp@1247: fp@1531: /** Deactivates the master. fp@1531: */ fp@1531: int ec_cdev_ioctl_deactivate( fp@1531: ec_master_t *master, /**< EtherCAT master. */ fp@1531: unsigned long arg, /**< ioctl() argument. */ fp@1531: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1531: ) fp@1531: { fp@1531: if (unlikely(!priv->requested)) fp@1531: return -EPERM; fp@1531: fp@1531: ecrt_master_deactivate(master); fp@1531: return 0; fp@1531: } fp@1531: martin@1585: martin@1585: /*****************************************************************************/ martin@1585: martin@1585: /** Set max. number of databytes in a cycle martin@1585: */ martin@1600: int ec_cdev_ioctl_set_send_interval( martin@1600: ec_master_t *master, /**< EtherCAT master. */ martin@1600: unsigned long arg, /**< ioctl() argument. */ martin@1600: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ martin@1600: ) martin@1600: { fp@1804: size_t send_interval; fp@1804: fp@1804: if (copy_from_user(&send_interval, (void __user *) arg, fp@1804: sizeof(send_interval))) { fp@1804: return -EFAULT; fp@1804: } fp@1804: fp@1804: if (down_interruptible(&master->master_sem)) fp@1804: return -EINTR; fp@1804: ec_master_set_send_interval(master,send_interval); martin@1585: up(&master->master_sem); martin@1585: martin@1585: return 0; martin@1585: } martin@1585: martin@1585: fp@1531: /*****************************************************************************/ fp@1531: fp@1247: /** Send frames. fp@1247: */ fp@1247: int ec_cdev_ioctl_send( fp@1247: ec_master_t *master, /**< EtherCAT master. */ fp@1247: unsigned long arg, /**< ioctl() argument. */ fp@1247: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1247: ) fp@1247: { fp@1507: if (unlikely(!priv->requested)) fp@1507: return -EPERM; fp@1247: fp@1489: down(&master->io_sem); fp@1247: ecrt_master_send(master); fp@1489: up(&master->io_sem); fp@1247: return 0; fp@1247: } fp@1247: fp@1247: /*****************************************************************************/ fp@1247: fp@1247: /** Receive frames. fp@1247: */ fp@1247: int ec_cdev_ioctl_receive( fp@1247: ec_master_t *master, /**< EtherCAT master. */ fp@1247: unsigned long arg, /**< ioctl() argument. */ fp@1247: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1247: ) fp@1247: { fp@1507: if (unlikely(!priv->requested)) fp@1507: return -EPERM; fp@1247: fp@1489: down(&master->io_sem); fp@1247: ecrt_master_receive(master); fp@1489: up(&master->io_sem); fp@1247: return 0; fp@1247: } fp@1247: fp@1255: /*****************************************************************************/ fp@1255: fp@1259: /** Get the master state. fp@1259: */ fp@1259: int ec_cdev_ioctl_master_state( fp@1259: ec_master_t *master, /**< EtherCAT master. */ fp@1259: unsigned long arg, /**< ioctl() argument. */ fp@1259: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1259: ) fp@1259: { fp@1259: ec_master_state_t data; fp@1259: fp@1507: if (unlikely(!priv->requested)) fp@1507: return -EPERM; fp@1259: fp@1259: ecrt_master_state(master, &data); fp@1259: fp@1259: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1259: return -EFAULT; fp@1259: fp@1259: return 0; fp@1259: } fp@1259: fp@1259: /*****************************************************************************/ fp@1259: fp@1454: /** Get the master state. fp@1454: */ fp@1454: int ec_cdev_ioctl_app_time( fp@1454: ec_master_t *master, /**< EtherCAT master. */ fp@1454: unsigned long arg, /**< ioctl() argument. */ fp@1454: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1454: ) fp@1454: { fp@1454: ec_ioctl_app_time_t data; fp@1454: fp@1507: if (unlikely(!priv->requested)) fp@1507: return -EPERM; fp@1454: fp@1454: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1454: return -EFAULT; fp@1454: } fp@1454: fp@1454: ecrt_master_application_time(master, data.app_time); fp@1454: return 0; fp@1454: } fp@1454: fp@1454: /*****************************************************************************/ fp@1454: fp@1413: /** Sync the reference clock. fp@1413: */ fp@1413: int ec_cdev_ioctl_sync_ref( fp@1413: ec_master_t *master, /**< EtherCAT master. */ fp@1413: unsigned long arg, /**< ioctl() argument. */ fp@1413: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1413: ) fp@1413: { fp@1507: if (unlikely(!priv->requested)) fp@1507: return -EPERM; fp@1413: fp@1489: down(&master->io_sem); fp@1434: ecrt_master_sync_reference_clock(master); fp@1489: up(&master->io_sem); fp@1413: return 0; fp@1413: } fp@1413: fp@1413: /*****************************************************************************/ fp@1413: fp@1413: /** Sync the slave clocks. fp@1413: */ fp@1413: int ec_cdev_ioctl_sync_slaves( fp@1413: ec_master_t *master, /**< EtherCAT master. */ fp@1413: unsigned long arg, /**< ioctl() argument. */ fp@1413: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1413: ) fp@1413: { fp@1507: if (unlikely(!priv->requested)) fp@1507: return -EPERM; fp@1413: fp@1489: down(&master->io_sem); fp@1413: ecrt_master_sync_slave_clocks(master); fp@1489: up(&master->io_sem); fp@1413: return 0; fp@1413: } fp@1413: fp@1413: /*****************************************************************************/ fp@1413: fp@1535: /** Queue the sync monitoring datagram. fp@1535: */ fp@1535: int ec_cdev_ioctl_sync_mon_queue( fp@1535: ec_master_t *master, /**< EtherCAT master. */ fp@1535: unsigned long arg, /**< ioctl() argument. */ fp@1535: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1535: ) fp@1535: { fp@1535: if (unlikely(!priv->requested)) fp@1535: return -EPERM; fp@1535: fp@1535: down(&master->io_sem); fp@1535: ecrt_master_sync_monitor_queue(master); fp@1535: up(&master->io_sem); fp@1535: return 0; fp@1535: } fp@1535: fp@1535: /*****************************************************************************/ fp@1535: fp@1535: /** Processes the sync monitoring datagram. fp@1535: */ fp@1535: int ec_cdev_ioctl_sync_mon_process( fp@1535: ec_master_t *master, /**< EtherCAT master. */ fp@1535: unsigned long arg, /**< ioctl() argument. */ fp@1535: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1535: ) fp@1535: { fp@1535: uint32_t time_diff; fp@1535: fp@1535: if (unlikely(!priv->requested)) fp@1535: return -EPERM; fp@1535: fp@1535: down(&master->io_sem); fp@1535: time_diff = ecrt_master_sync_monitor_process(master); fp@1535: up(&master->io_sem); fp@1535: fp@1535: if (copy_to_user((void __user *) arg, &time_diff, sizeof(time_diff))) fp@1535: return -EFAULT; fp@1535: fp@1535: return 0; fp@1535: } fp@1535: fp@1535: /*****************************************************************************/ fp@1535: fp@1509: /** Configure a sync manager. fp@1255: */ fp@1255: int ec_cdev_ioctl_sc_sync( fp@1255: ec_master_t *master, /**< EtherCAT master. */ fp@1255: unsigned long arg, /**< ioctl() argument. */ fp@1255: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1255: ) fp@1255: { fp@1255: ec_ioctl_config_t data; fp@1255: ec_slave_config_t *sc; fp@1255: unsigned int i; fp@1255: int ret = 0; fp@1255: fp@1507: if (unlikely(!priv->requested)) { fp@1255: ret = -EPERM; fp@1255: goto out_return; fp@1255: } fp@1255: fp@1255: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1255: ret = -EFAULT; fp@1255: goto out_return; fp@1255: } fp@1255: fp@1255: if (down_interruptible(&master->master_sem)) { fp@1255: ret = -EINTR; fp@1255: goto out_return; fp@1255: } fp@1255: fp@1255: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1313: ret = -ENOENT; fp@1255: goto out_up; fp@1255: } fp@1255: fp@1255: for (i = 0; i < EC_MAX_SYNC_MANAGERS; i++) { fp@1509: if (data.syncs[i].config_this) { fp@1509: if (ecrt_slave_config_sync_manager(sc, i, data.syncs[i].dir, fp@1509: data.syncs[i].watchdog_mode)) { fp@1255: ret = -EINVAL; fp@1255: goto out_up; fp@1255: } fp@1255: } fp@1255: } fp@1255: fp@1255: out_up: fp@1255: up(&master->master_sem); fp@1255: out_return: fp@1255: return ret; fp@1255: } fp@1255: fp@1255: /*****************************************************************************/ fp@1255: fp@1509: /** Configure a slave's watchdogs. fp@1509: */ fp@1509: int ec_cdev_ioctl_sc_watchdog( fp@1509: ec_master_t *master, /**< EtherCAT master. */ fp@1509: unsigned long arg, /**< ioctl() argument. */ fp@1509: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1509: ) fp@1509: { fp@1509: ec_ioctl_config_t data; fp@1509: ec_slave_config_t *sc; fp@1509: int ret = 0; fp@1509: fp@1509: if (unlikely(!priv->requested)) { fp@1509: ret = -EPERM; fp@1509: goto out_return; fp@1509: } fp@1509: fp@1509: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1509: ret = -EFAULT; fp@1509: goto out_return; fp@1509: } fp@1509: fp@1509: if (down_interruptible(&master->master_sem)) { fp@1509: ret = -EINTR; fp@1509: goto out_return; fp@1509: } fp@1509: fp@1509: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1509: ret = -ENOENT; fp@1509: goto out_up; fp@1509: } fp@1509: fp@1509: ecrt_slave_config_watchdog(sc, fp@1509: data.watchdog_divider, data.watchdog_intervals); fp@1509: fp@1509: out_up: fp@1509: up(&master->master_sem); fp@1509: out_return: fp@1509: return ret; fp@1509: } fp@1509: fp@1509: /*****************************************************************************/ fp@1509: fp@1327: /** Add a PDO to the assignment. fp@1255: */ fp@1255: int ec_cdev_ioctl_sc_add_pdo( fp@1255: ec_master_t *master, /**< EtherCAT master. */ fp@1255: unsigned long arg, /**< ioctl() argument. */ fp@1255: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1255: ) fp@1255: { fp@1255: ec_ioctl_config_pdo_t data; fp@1255: ec_slave_config_t *sc; fp@1255: fp@1507: if (unlikely(!priv->requested)) fp@1255: return -EPERM; fp@1255: fp@1255: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1255: return -EFAULT; fp@1255: fp@1255: if (down_interruptible(&master->master_sem)) fp@1255: return -EINTR; fp@1255: fp@1255: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1255: up(&master->master_sem); fp@1313: return -ENOENT; fp@1255: } fp@1255: fp@1255: up(&master->master_sem); // FIXME fp@1255: fp@1255: return ecrt_slave_config_pdo_assign_add(sc, data.sync_index, data.index); fp@1255: } fp@1255: fp@1255: /*****************************************************************************/ fp@1255: fp@1327: /** Clears the PDO assignment. fp@1255: */ fp@1255: int ec_cdev_ioctl_sc_clear_pdos( fp@1255: ec_master_t *master, /**< EtherCAT master. */ fp@1255: unsigned long arg, /**< ioctl() argument. */ fp@1255: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1255: ) fp@1255: { fp@1255: ec_ioctl_config_pdo_t data; fp@1255: ec_slave_config_t *sc; fp@1255: fp@1507: if (unlikely(!priv->requested)) fp@1255: return -EPERM; fp@1255: fp@1255: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1255: return -EFAULT; fp@1255: fp@1255: if (down_interruptible(&master->master_sem)) fp@1255: return -EINTR; fp@1255: fp@1255: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1255: up(&master->master_sem); fp@1313: return -ENOENT; fp@1255: } fp@1255: fp@1255: up(&master->master_sem); // FIXME fp@1255: fp@1255: ecrt_slave_config_pdo_assign_clear(sc, data.sync_index); fp@1255: return 0; fp@1255: } fp@1255: fp@1255: /*****************************************************************************/ fp@1255: fp@1327: /** Add an entry to a PDO's mapping. fp@1255: */ fp@1255: int ec_cdev_ioctl_sc_add_entry( fp@1255: ec_master_t *master, /**< EtherCAT master. */ fp@1255: unsigned long arg, /**< ioctl() argument. */ fp@1255: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1255: ) fp@1255: { fp@1255: ec_ioctl_add_pdo_entry_t data; fp@1255: ec_slave_config_t *sc; fp@1255: fp@1507: if (unlikely(!priv->requested)) fp@1255: return -EPERM; fp@1255: fp@1255: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1255: return -EFAULT; fp@1255: fp@1255: if (down_interruptible(&master->master_sem)) fp@1255: return -EINTR; fp@1255: fp@1255: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1255: up(&master->master_sem); fp@1313: return -ENOENT; fp@1255: } fp@1255: fp@1255: up(&master->master_sem); // FIXME fp@1255: fp@1255: return ecrt_slave_config_pdo_mapping_add(sc, data.pdo_index, fp@1255: data.entry_index, data.entry_subindex, data.entry_bit_length); fp@1255: } fp@1255: fp@1255: /*****************************************************************************/ fp@1255: fp@1327: /** Clears the mapping of a PDO. fp@1255: */ fp@1255: int ec_cdev_ioctl_sc_clear_entries( fp@1255: ec_master_t *master, /**< EtherCAT master. */ fp@1255: unsigned long arg, /**< ioctl() argument. */ fp@1255: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1255: ) fp@1255: { fp@1255: ec_ioctl_config_pdo_t data; fp@1255: ec_slave_config_t *sc; fp@1255: fp@1507: if (unlikely(!priv->requested)) fp@1255: return -EPERM; fp@1255: fp@1255: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1255: return -EFAULT; fp@1255: fp@1255: if (down_interruptible(&master->master_sem)) fp@1255: return -EINTR; fp@1255: fp@1255: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1255: up(&master->master_sem); fp@1313: return -ENOENT; fp@1255: } fp@1255: fp@1255: up(&master->master_sem); // FIXME fp@1255: fp@1255: ecrt_slave_config_pdo_mapping_clear(sc, data.index); fp@1255: return 0; fp@1255: } fp@1255: fp@1255: /*****************************************************************************/ fp@1255: fp@1327: /** Registers a PDO entry. fp@1255: */ fp@1255: int ec_cdev_ioctl_sc_reg_pdo_entry( fp@1255: ec_master_t *master, /**< EtherCAT master. */ fp@1255: unsigned long arg, /**< ioctl() argument. */ fp@1255: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1255: ) fp@1255: { fp@1255: ec_ioctl_reg_pdo_entry_t data; fp@1255: ec_slave_config_t *sc; fp@1255: ec_domain_t *domain; fp@1255: int ret; fp@1255: fp@1507: if (unlikely(!priv->requested)) fp@1255: return -EPERM; fp@1255: fp@1255: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1255: return -EFAULT; fp@1255: fp@1255: if (down_interruptible(&master->master_sem)) fp@1255: return -EINTR; fp@1255: fp@1255: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1255: up(&master->master_sem); fp@1313: return -ENOENT; fp@1255: } fp@1255: fp@1255: if (!(domain = ec_master_find_domain(master, data.domain_index))) { fp@1255: up(&master->master_sem); fp@1313: return -ENOENT; fp@1255: } fp@1255: fp@1255: up(&master->master_sem); // FIXME fp@1255: fp@1255: ret = ecrt_slave_config_reg_pdo_entry(sc, data.entry_index, fp@1255: data.entry_subindex, domain, &data.bit_position); fp@1255: fp@1255: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1255: return -EFAULT; fp@1255: fp@1255: return ret; fp@1255: } fp@1255: fp@1255: /*****************************************************************************/ fp@1255: fp@1448: /** Sets the DC AssignActivate word and the sync signal times. fp@1448: */ fp@1448: int ec_cdev_ioctl_sc_dc( fp@1413: ec_master_t *master, /**< EtherCAT master. */ fp@1413: unsigned long arg, /**< ioctl() argument. */ fp@1413: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1413: ) fp@1413: { fp@1455: ec_ioctl_config_t data; fp@1413: ec_slave_config_t *sc; fp@1413: fp@1507: if (unlikely(!priv->requested)) fp@1413: return -EPERM; fp@1413: fp@1413: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1413: return -EFAULT; fp@1413: fp@1413: if (down_interruptible(&master->master_sem)) fp@1413: return -EINTR; fp@1413: fp@1413: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1413: up(&master->master_sem); fp@1413: return -ENOENT; fp@1413: } fp@1413: fp@1455: ecrt_slave_config_dc(sc, data.dc_assign_activate, fp@1455: data.dc_sync[0].cycle_time, fp@1455: data.dc_sync[0].shift_time, fp@1455: data.dc_sync[1].cycle_time, fp@1455: data.dc_sync[1].shift_time); fp@1413: fp@1413: up(&master->master_sem); fp@1413: fp@1413: return 0; fp@1413: } fp@1413: fp@1413: /*****************************************************************************/ fp@1413: fp@1327: /** Configures an SDO. fp@1255: */ fp@1255: int ec_cdev_ioctl_sc_sdo( fp@1255: ec_master_t *master, /**< EtherCAT master. */ fp@1255: unsigned long arg, /**< ioctl() argument. */ fp@1255: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1255: ) fp@1255: { fp@1255: ec_ioctl_sc_sdo_t data; fp@1255: ec_slave_config_t *sc; fp@1255: uint8_t *sdo_data = NULL; fp@1255: int ret; fp@1255: fp@1507: if (unlikely(!priv->requested)) fp@1255: return -EPERM; fp@1255: fp@1255: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1255: return -EFAULT; fp@1255: fp@1255: if (!data.size) fp@1255: return -EINVAL; fp@1255: fp@1255: if (!(sdo_data = kmalloc(data.size, GFP_KERNEL))) { fp@1255: return -ENOMEM; fp@1255: } fp@1255: fp@1255: if (copy_from_user(sdo_data, (void __user *) data.data, data.size)) { fp@1255: kfree(sdo_data); fp@1255: return -EFAULT; fp@1255: } fp@1255: fp@1255: if (down_interruptible(&master->master_sem)) { fp@1255: kfree(sdo_data); fp@1255: return -EINTR; fp@1255: } fp@1255: fp@1255: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1255: up(&master->master_sem); fp@1255: kfree(sdo_data); fp@1313: return -ENOENT; fp@1255: } fp@1255: fp@1255: up(&master->master_sem); // FIXME fp@1255: fp@1526: if (data.complete_access) { fp@1831: ret = ecrt_slave_config_complete_sdo(sc, fp@1831: data.index, sdo_data, data.size); fp@1526: } else { fp@1526: ret = ecrt_slave_config_sdo(sc, data.index, data.subindex, sdo_data, fp@1526: data.size); fp@1526: } fp@1255: kfree(sdo_data); fp@1255: return ret; fp@1255: } fp@1255: fp@1258: /*****************************************************************************/ fp@1258: fp@1352: /** Create an SDO request. fp@1352: */ fp@1352: int ec_cdev_ioctl_sc_create_sdo_request( fp@1352: ec_master_t *master, /**< EtherCAT master. */ fp@1352: unsigned long arg, /**< ioctl() argument. */ fp@1352: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1352: ) fp@1352: { fp@1352: ec_ioctl_sdo_request_t data; fp@1352: ec_slave_config_t *sc; fp@1352: ec_sdo_request_t *req; fp@1352: fp@1507: if (unlikely(!priv->requested)) fp@1507: return -EPERM; fp@1352: fp@1352: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1352: return -EFAULT; fp@1352: } fp@1352: fp@1352: data.request_index = 0; fp@1352: fp@1352: if (down_interruptible(&master->master_sem)) fp@1352: return -EINTR; fp@1352: fp@1352: sc = ec_master_get_config(master, data.config_index); fp@1352: if (!sc) { fp@1352: up(&master->master_sem); fp@1352: return -ENOENT; fp@1352: } fp@1352: fp@1352: list_for_each_entry(req, &sc->sdo_requests, list) { fp@1352: data.request_index++; fp@1352: } fp@1352: fp@1352: up(&master->master_sem); fp@1352: fp@1352: req = ecrt_slave_config_create_sdo_request_err(sc, data.sdo_index, fp@1352: data.sdo_subindex, data.size); fp@1352: if (IS_ERR(req)) fp@1352: return PTR_ERR(req); fp@1352: fp@1352: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1352: return -EFAULT; fp@1352: fp@1352: return 0; fp@1352: } fp@1352: fp@1352: /*****************************************************************************/ fp@1352: fp@1264: /** Create a VoE handler. fp@1264: */ fp@1264: int ec_cdev_ioctl_sc_create_voe_handler( fp@1264: ec_master_t *master, /**< EtherCAT master. */ fp@1264: unsigned long arg, /**< ioctl() argument. */ fp@1264: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1264: ) fp@1264: { fp@1264: ec_ioctl_voe_t data; fp@1264: ec_slave_config_t *sc; fp@1264: ec_voe_handler_t *voe; fp@1264: fp@1507: if (unlikely(!priv->requested)) fp@1507: return -EPERM; fp@1264: fp@1264: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1264: return -EFAULT; fp@1264: } fp@1264: fp@1264: data.voe_index = 0; fp@1264: fp@1264: if (down_interruptible(&master->master_sem)) fp@1264: return -EINTR; fp@1264: fp@1264: sc = ec_master_get_config(master, data.config_index); fp@1264: if (!sc) { fp@1264: up(&master->master_sem); fp@1313: return -ENOENT; fp@1264: } fp@1264: fp@1264: list_for_each_entry(voe, &sc->voe_handlers, list) { fp@1264: data.voe_index++; fp@1264: } fp@1264: fp@1264: up(&master->master_sem); fp@1264: fp@1312: voe = ecrt_slave_config_create_voe_handler_err(sc, data.size); fp@1312: if (IS_ERR(voe)) fp@1312: return PTR_ERR(voe); fp@1264: fp@1264: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1264: return -EFAULT; fp@1264: fp@1264: return 0; fp@1264: } fp@1264: fp@1264: /*****************************************************************************/ fp@1264: fp@1259: /** Get the slave configuration's state. fp@1259: */ fp@1259: int ec_cdev_ioctl_sc_state( fp@1259: ec_master_t *master, /**< EtherCAT master. */ fp@1259: unsigned long arg, /**< ioctl() argument. */ fp@1259: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1259: ) fp@1259: { fp@1259: ec_ioctl_sc_state_t data; fp@1259: const ec_slave_config_t *sc; fp@1259: ec_slave_config_state_t state; fp@1259: fp@1507: if (unlikely(!priv->requested)) fp@1507: return -EPERM; fp@1259: fp@1259: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1259: return -EFAULT; fp@1259: } fp@1259: fp@1259: if (down_interruptible(&master->master_sem)) fp@1259: return -EINTR; fp@1259: fp@1259: if (!(sc = ec_master_get_config_const(master, data.config_index))) { fp@1259: up(&master->master_sem); fp@1313: return -ENOENT; fp@1259: } fp@1259: fp@1259: ecrt_slave_config_state(sc, &state); fp@1259: fp@1259: up(&master->master_sem); fp@1259: fp@1259: if (copy_to_user((void __user *) data.state, &state, sizeof(state))) fp@1259: return -EFAULT; fp@1259: fp@1259: return 0; fp@1259: } fp@1259: fp@1259: /*****************************************************************************/ fp@1259: fp@1258: /** Gets the domain's offset in the total process data. fp@1258: */ fp@1258: int ec_cdev_ioctl_domain_offset( fp@1258: ec_master_t *master, /**< EtherCAT master. */ fp@1258: unsigned long arg, /**< ioctl() argument. */ fp@1258: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1258: ) fp@1258: { fp@1258: int offset = 0; fp@1258: const ec_domain_t *domain; fp@1258: fp@1507: if (unlikely(!priv->requested)) fp@1258: return -EPERM; fp@1258: fp@1258: if (down_interruptible(&master->master_sem)) { fp@1258: return -EINTR; fp@1258: } fp@1258: fp@1258: list_for_each_entry(domain, &master->domains, list) { fp@1258: if (domain->index == arg) { fp@1258: up(&master->master_sem); fp@1258: return offset; fp@1258: } fp@1258: offset += ecrt_domain_size(domain); fp@1258: } fp@1258: fp@1258: up(&master->master_sem); fp@1313: return -ENOENT; fp@1258: } fp@1258: fp@1258: /*****************************************************************************/ fp@1258: fp@1258: /** Process the domain. fp@1258: */ fp@1258: int ec_cdev_ioctl_domain_process( fp@1258: ec_master_t *master, /**< EtherCAT master. */ fp@1258: unsigned long arg, /**< ioctl() argument. */ fp@1258: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1258: ) fp@1258: { fp@1258: ec_domain_t *domain; fp@1258: fp@1507: if (unlikely(!priv->requested)) fp@1258: return -EPERM; fp@1258: fp@1258: if (down_interruptible(&master->master_sem)) fp@1258: return -EINTR; fp@1258: fp@1258: if (!(domain = ec_master_find_domain(master, arg))) { fp@1258: up(&master->master_sem); fp@1313: return -ENOENT; fp@1258: } fp@1258: fp@1258: ecrt_domain_process(domain); fp@1258: up(&master->master_sem); fp@1258: return 0; fp@1258: } fp@1258: fp@1258: /*****************************************************************************/ fp@1258: fp@1258: /** Queue the domain. fp@1258: */ fp@1258: int ec_cdev_ioctl_domain_queue( fp@1258: ec_master_t *master, /**< EtherCAT master. */ fp@1258: unsigned long arg, /**< ioctl() argument. */ fp@1258: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1258: ) fp@1258: { fp@1258: ec_domain_t *domain; fp@1258: fp@1507: if (unlikely(!priv->requested)) fp@1258: return -EPERM; fp@1258: fp@1258: if (down_interruptible(&master->master_sem)) fp@1258: return -EINTR; fp@1258: fp@1258: if (!(domain = ec_master_find_domain(master, arg))) { fp@1258: up(&master->master_sem); fp@1313: return -ENOENT; fp@1258: } fp@1258: fp@1258: ecrt_domain_queue(domain); fp@1258: up(&master->master_sem); fp@1258: return 0; fp@1258: } fp@1258: fp@1259: /*****************************************************************************/ fp@1259: fp@1259: /** Get the domain state. fp@1259: */ fp@1259: int ec_cdev_ioctl_domain_state( fp@1259: ec_master_t *master, /**< EtherCAT master. */ fp@1259: unsigned long arg, /**< ioctl() argument. */ fp@1259: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1259: ) fp@1259: { fp@1259: ec_ioctl_domain_state_t data; fp@1259: const ec_domain_t *domain; fp@1259: ec_domain_state_t state; fp@1259: fp@1507: if (unlikely(!priv->requested)) fp@1507: return -EPERM; fp@1259: fp@1259: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1259: return -EFAULT; fp@1259: } fp@1259: fp@1259: if (down_interruptible(&master->master_sem)) fp@1259: return -EINTR; fp@1259: fp@1259: if (!(domain = ec_master_find_domain_const(master, data.domain_index))) { fp@1259: up(&master->master_sem); fp@1313: return -ENOENT; fp@1259: } fp@1259: fp@1259: ecrt_domain_state(domain, &state); fp@1259: fp@1259: up(&master->master_sem); fp@1259: fp@1259: if (copy_to_user((void __user *) data.state, &state, sizeof(state))) fp@1259: return -EFAULT; fp@1259: fp@1259: return 0; fp@1259: } fp@1259: fp@1264: /*****************************************************************************/ fp@1264: fp@1352: /** Sets an SDO request's timeout. fp@1352: */ fp@1352: int ec_cdev_ioctl_sdo_request_timeout( fp@1352: ec_master_t *master, /**< EtherCAT master. */ fp@1352: unsigned long arg, /**< ioctl() argument. */ fp@1352: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1352: ) fp@1352: { fp@1352: ec_ioctl_sdo_request_t data; fp@1352: ec_slave_config_t *sc; fp@1352: ec_sdo_request_t *req; fp@1352: fp@1507: if (unlikely(!priv->requested)) fp@1352: return -EPERM; fp@1352: fp@1352: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1352: return -EFAULT; fp@1352: fp@1352: if (down_interruptible(&master->master_sem)) fp@1352: return -EINTR; fp@1352: fp@1352: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1352: up(&master->master_sem); fp@1352: return -ENOENT; fp@1352: } fp@1352: fp@1352: if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { fp@1352: up(&master->master_sem); fp@1352: return -ENOENT; fp@1352: } fp@1352: fp@1352: up(&master->master_sem); fp@1352: fp@1352: ecrt_sdo_request_timeout(req, data.timeout); fp@1352: return 0; fp@1352: } fp@1352: fp@1352: /*****************************************************************************/ fp@1352: fp@1352: /** Gets an SDO request's state. fp@1352: */ fp@1352: int ec_cdev_ioctl_sdo_request_state( fp@1352: ec_master_t *master, /**< EtherCAT master. */ fp@1352: unsigned long arg, /**< ioctl() argument. */ fp@1352: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1352: ) fp@1352: { fp@1352: ec_ioctl_sdo_request_t data; fp@1352: ec_slave_config_t *sc; fp@1352: ec_sdo_request_t *req; fp@1352: fp@1507: if (unlikely(!priv->requested)) fp@1352: return -EPERM; fp@1352: fp@1352: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1352: return -EFAULT; fp@1352: fp@1352: if (down_interruptible(&master->master_sem)) fp@1352: return -EINTR; fp@1352: fp@1352: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1352: up(&master->master_sem); fp@1352: return -ENOENT; fp@1352: } fp@1352: fp@1352: if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { fp@1352: up(&master->master_sem); fp@1352: return -ENOENT; fp@1352: } fp@1352: fp@1352: data.state = ecrt_sdo_request_state(req); fp@1352: if (data.state == EC_REQUEST_SUCCESS && req->dir == EC_DIR_INPUT) fp@1352: data.size = ecrt_sdo_request_data_size(req); fp@1352: else fp@1352: data.size = 0; fp@1352: fp@1352: up(&master->master_sem); fp@1352: fp@1352: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1352: return -EFAULT; fp@1352: fp@1352: return 0; fp@1352: } fp@1352: fp@1352: /*****************************************************************************/ fp@1352: fp@1352: /** Starts an SDO read operation. fp@1352: */ fp@1352: int ec_cdev_ioctl_sdo_request_read( fp@1352: ec_master_t *master, /**< EtherCAT master. */ fp@1352: unsigned long arg, /**< ioctl() argument. */ fp@1352: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1352: ) fp@1352: { fp@1352: ec_ioctl_sdo_request_t data; fp@1352: ec_slave_config_t *sc; fp@1352: ec_sdo_request_t *req; fp@1352: fp@1507: if (unlikely(!priv->requested)) fp@1352: return -EPERM; fp@1352: fp@1352: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1352: return -EFAULT; fp@1352: fp@1352: if (down_interruptible(&master->master_sem)) fp@1352: return -EINTR; fp@1352: fp@1352: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1352: up(&master->master_sem); fp@1352: return -ENOENT; fp@1352: } fp@1352: fp@1352: if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { fp@1352: up(&master->master_sem); fp@1352: return -ENOENT; fp@1352: } fp@1352: fp@1352: up(&master->master_sem); fp@1352: fp@1352: ecrt_sdo_request_read(req); fp@1352: return 0; fp@1352: } fp@1352: fp@1352: /*****************************************************************************/ fp@1352: fp@1352: /** Starts an SDO write operation. fp@1352: */ fp@1352: int ec_cdev_ioctl_sdo_request_write( fp@1352: ec_master_t *master, /**< EtherCAT master. */ fp@1352: unsigned long arg, /**< ioctl() argument. */ fp@1352: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1352: ) fp@1352: { fp@1352: ec_ioctl_sdo_request_t data; fp@1352: ec_slave_config_t *sc; fp@1352: ec_sdo_request_t *req; fp@1361: int ret; fp@1352: fp@1507: if (unlikely(!priv->requested)) fp@1352: return -EPERM; fp@1352: fp@1352: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1352: return -EFAULT; fp@1352: fp@1361: if (!data.size) { fp@1361: EC_ERR("Sdo download: Data size may not be zero!\n"); fp@1361: return -EINVAL; fp@1361: } fp@1361: fp@1352: if (down_interruptible(&master->master_sem)) fp@1352: return -EINTR; fp@1352: fp@1352: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1352: up(&master->master_sem); fp@1352: return -ENOENT; fp@1352: } fp@1352: fp@1352: if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { fp@1352: up(&master->master_sem); fp@1352: return -ENOENT; fp@1352: } fp@1352: fp@1352: up(&master->master_sem); fp@1352: fp@1361: ret = ec_sdo_request_alloc(req, data.size); fp@1361: if (ret) fp@1361: return ret; fp@1361: fp@1361: if (copy_from_user(req->data, (void __user *) data.data, data.size)) fp@1361: return -EFAULT; fp@1361: fp@1361: req->data_size = data.size; fp@1352: ecrt_sdo_request_write(req); fp@1352: return 0; fp@1352: } fp@1352: fp@1352: /*****************************************************************************/ fp@1352: fp@1352: /** Read SDO data. fp@1352: */ fp@1352: int ec_cdev_ioctl_sdo_request_data( fp@1352: ec_master_t *master, /**< EtherCAT master. */ fp@1352: unsigned long arg, /**< ioctl() argument. */ fp@1352: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1352: ) fp@1352: { fp@1352: ec_ioctl_sdo_request_t data; fp@1352: ec_slave_config_t *sc; fp@1352: ec_sdo_request_t *req; fp@1352: fp@1507: if (unlikely(!priv->requested)) fp@1352: return -EPERM; fp@1352: fp@1352: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1352: return -EFAULT; fp@1352: fp@1352: if (down_interruptible(&master->master_sem)) fp@1352: return -EINTR; fp@1352: fp@1352: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1352: up(&master->master_sem); fp@1352: return -ENOENT; fp@1352: } fp@1352: fp@1352: if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { fp@1352: up(&master->master_sem); fp@1352: return -ENOENT; fp@1352: } fp@1352: fp@1352: up(&master->master_sem); fp@1352: fp@1362: if (copy_to_user((void __user *) data.data, ecrt_sdo_request_data(req), fp@1362: ecrt_sdo_request_data_size(req))) fp@1362: return -EFAULT; fp@1362: fp@1352: return 0; fp@1352: } fp@1352: fp@1352: /*****************************************************************************/ fp@1352: fp@1264: /** Sets the VoE send header. fp@1264: */ fp@1264: int ec_cdev_ioctl_voe_send_header( fp@1264: ec_master_t *master, /**< EtherCAT master. */ fp@1264: unsigned long arg, /**< ioctl() argument. */ fp@1264: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1264: ) fp@1264: { fp@1264: ec_ioctl_voe_t data; fp@1264: ec_slave_config_t *sc; fp@1264: ec_voe_handler_t *voe; fp@1264: uint32_t vendor_id; fp@1264: uint16_t vendor_type; fp@1264: fp@1507: if (unlikely(!priv->requested)) fp@1264: return -EPERM; fp@1264: fp@1264: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1264: return -EFAULT; fp@1264: fp@1264: if (get_user(vendor_id, data.vendor_id)) fp@1264: return -EFAULT; fp@1264: fp@1264: if (get_user(vendor_type, data.vendor_type)) fp@1264: return -EFAULT; fp@1264: fp@1264: if (down_interruptible(&master->master_sem)) fp@1264: return -EINTR; fp@1264: fp@1264: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1264: up(&master->master_sem); fp@1313: return -ENOENT; fp@1264: } fp@1264: fp@1264: if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { fp@1264: up(&master->master_sem); fp@1313: return -ENOENT; fp@1264: } fp@1264: fp@1264: up(&master->master_sem); fp@1264: fp@1264: ecrt_voe_handler_send_header(voe, vendor_id, vendor_type); fp@1264: return 0; fp@1264: } fp@1264: fp@1264: /*****************************************************************************/ fp@1264: fp@1264: /** Gets the received VoE header. fp@1264: */ fp@1264: int ec_cdev_ioctl_voe_rec_header( fp@1264: ec_master_t *master, /**< EtherCAT master. */ fp@1264: unsigned long arg, /**< ioctl() argument. */ fp@1264: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1264: ) fp@1264: { fp@1264: ec_ioctl_voe_t data; fp@1264: ec_slave_config_t *sc; fp@1264: ec_voe_handler_t *voe; fp@1264: uint32_t vendor_id; fp@1264: uint16_t vendor_type; fp@1264: fp@1507: if (unlikely(!priv->requested)) fp@1264: return -EPERM; fp@1264: fp@1264: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1264: return -EFAULT; fp@1264: fp@1264: if (down_interruptible(&master->master_sem)) fp@1264: return -EINTR; fp@1264: fp@1264: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1264: up(&master->master_sem); fp@1313: return -ENOENT; fp@1264: } fp@1264: fp@1264: if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { fp@1264: up(&master->master_sem); fp@1313: return -ENOENT; fp@1264: } fp@1264: fp@1264: ecrt_voe_handler_received_header(voe, &vendor_id, &vendor_type); fp@1264: fp@1264: up(&master->master_sem); fp@1264: fp@1264: if (likely(data.vendor_id)) fp@1264: if (put_user(vendor_id, data.vendor_id)) fp@1264: return -EFAULT; fp@1264: fp@1264: if (likely(data.vendor_type)) fp@1264: if (put_user(vendor_type, data.vendor_type)) fp@1264: return -EFAULT; fp@1264: fp@1264: return 0; fp@1264: } fp@1264: fp@1264: /*****************************************************************************/ fp@1264: fp@1264: /** Starts a VoE read operation. fp@1264: */ fp@1264: int ec_cdev_ioctl_voe_read( fp@1264: ec_master_t *master, /**< EtherCAT master. */ fp@1264: unsigned long arg, /**< ioctl() argument. */ fp@1264: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1264: ) fp@1264: { fp@1264: ec_ioctl_voe_t data; fp@1264: ec_slave_config_t *sc; fp@1264: ec_voe_handler_t *voe; fp@1264: fp@1507: if (unlikely(!priv->requested)) fp@1264: return -EPERM; fp@1264: fp@1264: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1264: return -EFAULT; fp@1264: fp@1264: if (down_interruptible(&master->master_sem)) fp@1264: return -EINTR; fp@1264: fp@1264: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1264: up(&master->master_sem); fp@1313: return -ENOENT; fp@1264: } fp@1264: fp@1264: if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { fp@1264: up(&master->master_sem); fp@1313: return -ENOENT; fp@1264: } fp@1264: fp@1264: up(&master->master_sem); fp@1264: fp@1264: ecrt_voe_handler_read(voe); fp@1264: return 0; fp@1264: } fp@1264: fp@1264: /*****************************************************************************/ fp@1264: fp@1314: /** Starts a VoE read operation without sending a sync message first. fp@1314: */ fp@1314: int ec_cdev_ioctl_voe_read_nosync( fp@1314: ec_master_t *master, /**< EtherCAT master. */ fp@1314: unsigned long arg, /**< ioctl() argument. */ fp@1314: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1314: ) fp@1314: { fp@1314: ec_ioctl_voe_t data; fp@1314: ec_slave_config_t *sc; fp@1314: ec_voe_handler_t *voe; fp@1314: fp@1507: if (unlikely(!priv->requested)) fp@1314: return -EPERM; fp@1314: fp@1314: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1314: return -EFAULT; fp@1314: fp@1314: if (down_interruptible(&master->master_sem)) fp@1314: return -EINTR; fp@1314: fp@1314: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1314: up(&master->master_sem); fp@1314: return -ENOENT; fp@1314: } fp@1314: fp@1314: if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { fp@1314: up(&master->master_sem); fp@1314: return -ENOENT; fp@1314: } fp@1314: fp@1314: up(&master->master_sem); fp@1314: fp@1314: ecrt_voe_handler_read_nosync(voe); fp@1314: return 0; fp@1314: } fp@1314: fp@1314: /*****************************************************************************/ fp@1314: fp@1264: /** Starts a VoE write operation. fp@1264: */ fp@1264: int ec_cdev_ioctl_voe_write( fp@1264: ec_master_t *master, /**< EtherCAT master. */ fp@1264: unsigned long arg, /**< ioctl() argument. */ fp@1264: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1264: ) fp@1264: { fp@1264: ec_ioctl_voe_t data; fp@1264: ec_slave_config_t *sc; fp@1264: ec_voe_handler_t *voe; fp@1264: fp@1507: if (unlikely(!priv->requested)) fp@1264: return -EPERM; fp@1264: fp@1264: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1264: return -EFAULT; fp@1264: fp@1264: if (down_interruptible(&master->master_sem)) fp@1264: return -EINTR; fp@1264: fp@1264: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1264: up(&master->master_sem); fp@1313: return -ENOENT; fp@1264: } fp@1264: fp@1264: if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { fp@1264: up(&master->master_sem); fp@1313: return -ENOENT; fp@1264: } fp@1264: fp@1264: up(&master->master_sem); fp@1264: fp@1264: if (data.size) { fp@1264: if (data.size > ec_voe_handler_mem_size(voe)) fp@1264: return -EOVERFLOW; fp@1264: fp@1264: if (copy_from_user(ecrt_voe_handler_data(voe), fp@1264: (void __user *) data.data, data.size)) fp@1264: return -EFAULT; fp@1264: } fp@1264: fp@1264: ecrt_voe_handler_write(voe, data.size); fp@1264: return 0; fp@1264: } fp@1264: fp@1264: /*****************************************************************************/ fp@1264: fp@1264: /** Executes the VoE state machine. fp@1264: */ fp@1264: int ec_cdev_ioctl_voe_exec( fp@1264: ec_master_t *master, /**< EtherCAT master. */ fp@1264: unsigned long arg, /**< ioctl() argument. */ fp@1264: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1264: ) fp@1264: { fp@1264: ec_ioctl_voe_t data; fp@1264: ec_slave_config_t *sc; fp@1264: ec_voe_handler_t *voe; fp@1264: fp@1507: if (unlikely(!priv->requested)) fp@1264: return -EPERM; fp@1264: fp@1264: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1264: return -EFAULT; fp@1264: fp@1264: if (down_interruptible(&master->master_sem)) fp@1264: return -EINTR; fp@1264: fp@1264: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1264: up(&master->master_sem); fp@1313: return -ENOENT; fp@1264: } fp@1264: fp@1264: if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { fp@1264: up(&master->master_sem); fp@1313: return -ENOENT; fp@1264: } fp@1264: fp@1264: up(&master->master_sem); fp@1264: fp@1264: data.state = ecrt_voe_handler_execute(voe); fp@1264: if (data.state == EC_REQUEST_SUCCESS && voe->dir == EC_DIR_INPUT) fp@1264: data.size = ecrt_voe_handler_data_size(voe); fp@1350: else fp@1350: data.size = 0; fp@1264: fp@1264: if (copy_to_user((void __user *) arg, &data, sizeof(data))) fp@1264: return -EFAULT; fp@1264: fp@1264: return 0; fp@1264: } fp@1264: fp@1264: /*****************************************************************************/ fp@1264: fp@1264: /** Reads the received VoE data. fp@1264: */ fp@1264: int ec_cdev_ioctl_voe_data( fp@1264: ec_master_t *master, /**< EtherCAT master. */ fp@1264: unsigned long arg, /**< ioctl() argument. */ fp@1264: ec_cdev_priv_t *priv /**< Private data structure of file handle. */ fp@1264: ) fp@1264: { fp@1264: ec_ioctl_voe_t data; fp@1264: ec_slave_config_t *sc; fp@1264: ec_voe_handler_t *voe; fp@1264: fp@1507: if (unlikely(!priv->requested)) fp@1264: return -EPERM; fp@1264: fp@1264: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) fp@1264: return -EFAULT; fp@1264: fp@1264: if (down_interruptible(&master->master_sem)) fp@1264: return -EINTR; fp@1264: fp@1264: if (!(sc = ec_master_get_config(master, data.config_index))) { fp@1264: up(&master->master_sem); fp@1313: return -ENOENT; fp@1264: } fp@1264: fp@1264: if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { fp@1264: up(&master->master_sem); fp@1313: return -ENOENT; fp@1264: } fp@1264: fp@1264: up(&master->master_sem); fp@1264: fp@1264: if (copy_to_user((void __user *) data.data, ecrt_voe_handler_data(voe), fp@1264: ecrt_voe_handler_data_size(voe))) fp@1264: return -EFAULT; fp@1264: fp@1264: return 0; fp@1264: } fp@1264: fp@1335: /*****************************************************************************/ fp@1335: fp@1335: /** Read a file from a slave via FoE. fp@1335: */ fp@1335: int ec_cdev_ioctl_slave_foe_read( fp@1335: ec_master_t *master, /**< EtherCAT master. */ fp@1335: unsigned long arg /**< ioctl() argument. */ fp@1335: ) fp@1335: { fp@1335: ec_ioctl_slave_foe_t data; fp@1335: ec_master_foe_request_t request; fp@1335: int retval; fp@1335: fp@1335: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1335: return -EFAULT; fp@1335: } fp@1335: fp@1335: ec_foe_request_init(&request.req, data.file_name); fp@1335: ec_foe_request_read(&request.req); fp@1335: ec_foe_request_alloc(&request.req, 10000); // FIXME fp@1335: fp@1335: if (down_interruptible(&master->master_sem)) fp@1335: return -EINTR; fp@1335: fp@1335: if (!(request.slave = ec_master_find_slave( fp@1335: master, 0, data.slave_position))) { fp@1335: up(&master->master_sem); fp@1335: ec_foe_request_clear(&request.req); fp@1335: EC_ERR("Slave %u does not exist!\n", data.slave_position); fp@1335: return -EINVAL; fp@1335: } fp@1335: fp@1335: // schedule request. martin@1597: list_add_tail(&request.list, &request.slave->foe_requests); fp@1335: fp@1335: up(&master->master_sem); fp@1335: fp@1336: if (master->debug_level) { fp@1336: EC_DBG("Scheduled FoE read request on slave %u.\n", fp@1336: request.slave->ring_position); fp@1336: } fp@1336: fp@1335: // wait for processing through FSM martin@1597: if (wait_event_interruptible(request.slave->foe_queue, fp@1335: request.req.state != EC_INT_REQUEST_QUEUED)) { fp@1335: // interrupted by signal fp@1335: down(&master->master_sem); fp@1335: if (request.req.state == EC_INT_REQUEST_QUEUED) { fp@1335: list_del(&request.list); fp@1335: up(&master->master_sem); fp@1335: ec_foe_request_clear(&request.req); fp@1335: return -EINTR; fp@1335: } fp@1335: // request already processing: interrupt not possible. fp@1335: up(&master->master_sem); fp@1335: } fp@1335: fp@1335: // wait until master FSM has finished processing fp@1831: wait_event(request.slave->foe_queue, fp@1831: request.req.state != EC_INT_REQUEST_BUSY); fp@1335: fp@1336: data.result = request.req.result; fp@1336: data.error_code = request.req.error_code; fp@1335: fp@1507: if (master->debug_level) { fp@1543: EC_DBG("Read %zd bytes via FoE (result = 0x%x).\n", fp@1507: request.req.data_size, request.req.result); fp@1507: } fp@1335: fp@1349: if (request.req.state != EC_INT_REQUEST_SUCCESS) { fp@1335: data.data_size = 0; fp@1335: retval = -EIO; fp@1335: } else { fp@1335: if (request.req.data_size > data.buffer_size) { fp@1335: EC_ERR("Buffer too small.\n"); fp@1335: ec_foe_request_clear(&request.req); fp@1335: return -EOVERFLOW; fp@1335: } fp@1335: data.data_size = request.req.data_size; fp@1335: if (copy_to_user((void __user *) data.buffer, fp@1335: request.req.buffer, data.data_size)) { fp@1335: ec_foe_request_clear(&request.req); fp@1335: return -EFAULT; fp@1335: } fp@1335: retval = 0; fp@1335: } fp@1335: fp@1335: if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { fp@1335: retval = -EFAULT; fp@1335: } fp@1335: fp@1336: if (master->debug_level) fp@1336: EC_DBG("FoE read request finished on slave %u.\n", fp@1336: request.slave->ring_position); fp@1336: fp@1335: ec_foe_request_clear(&request.req); fp@1336: fp@1335: return retval; fp@1335: } fp@1335: fp@1335: /*****************************************************************************/ fp@1335: fp@1335: /** Write a file to a slave via FoE fp@1335: */ fp@1335: int ec_cdev_ioctl_slave_foe_write( fp@1335: ec_master_t *master, /**< EtherCAT master. */ fp@1335: unsigned long arg /**< ioctl() argument. */ fp@1335: ) fp@1335: { fp@1335: ec_ioctl_slave_foe_t data; fp@1335: ec_master_foe_request_t request; fp@1335: int retval; fp@1335: fp@1335: if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { fp@1335: return -EFAULT; fp@1335: } fp@1335: fp@1335: INIT_LIST_HEAD(&request.list); fp@1335: fp@1335: ec_foe_request_init(&request.req, data.file_name); fp@1335: fp@1335: if (ec_foe_request_alloc(&request.req, data.buffer_size)) { fp@1335: ec_foe_request_clear(&request.req); fp@1335: return -ENOMEM; fp@1335: } fp@1335: if (copy_from_user(request.req.buffer, fp@1335: (void __user *) data.buffer, data.buffer_size)) { fp@1335: ec_foe_request_clear(&request.req); fp@1335: return -EFAULT; fp@1335: } fp@1335: request.req.data_size = data.buffer_size; fp@1335: ec_foe_request_write(&request.req); fp@1335: fp@1335: if (down_interruptible(&master->master_sem)) fp@1335: return -EINTR; fp@1335: fp@1335: if (!(request.slave = ec_master_find_slave( fp@1335: master, 0, data.slave_position))) { fp@1335: up(&master->master_sem); fp@1335: EC_ERR("Slave %u does not exist!\n", data.slave_position); fp@1335: ec_foe_request_clear(&request.req); fp@1335: return -EINVAL; fp@1335: } fp@1335: fp@1507: if (master->debug_level) { fp@1507: EC_DBG("Scheduling FoE write request.\n"); fp@1507: } fp@1335: fp@1335: // schedule FoE write request. martin@1597: list_add_tail(&request.list, &request.slave->foe_requests); fp@1335: fp@1335: up(&master->master_sem); fp@1335: fp@1335: // wait for processing through FSM martin@1597: if (wait_event_interruptible(request.slave->foe_queue, fp@1335: request.req.state != EC_INT_REQUEST_QUEUED)) { fp@1335: // interrupted by signal fp@1335: down(&master->master_sem); fp@1335: if (request.req.state == EC_INT_REQUEST_QUEUED) { fp@1335: // abort request fp@1335: list_del(&request.list); fp@1335: up(&master->master_sem); fp@1335: ec_foe_request_clear(&request.req); fp@1335: return -EINTR; fp@1335: } fp@1335: up(&master->master_sem); fp@1335: } fp@1335: fp@1335: // wait until master FSM has finished processing fp@1831: wait_event(request.slave->foe_queue, fp@1831: request.req.state != EC_INT_REQUEST_BUSY); fp@1335: fp@1336: data.result = request.req.result; fp@1336: data.error_code = request.req.error_code; fp@1335: fp@1349: retval = request.req.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; fp@1335: fp@1335: if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { fp@1335: retval = -EFAULT; fp@1335: } fp@1335: fp@1335: ec_foe_request_clear(&request.req); fp@1335: fp@1507: if (master->debug_level) { fp@1831: EC_DBG("Finished FoE writing.\n"); fp@1831: } fp@1831: fp@1831: return retval; fp@1831: } fp@1831: fp@1831: /*****************************************************************************/ fp@1831: fp@1831: /** Read an SoE IDN. fp@1831: */ fp@1831: int ec_cdev_ioctl_slave_soe_read( fp@1831: ec_master_t *master, /**< EtherCAT master. */ fp@1831: unsigned long arg /**< ioctl() argument. */ fp@1831: ) fp@1831: { fp@1837: ec_ioctl_slave_soe_read_t ioctl; fp@1831: ec_master_soe_request_t request; fp@1831: int retval; fp@1831: fp@1837: if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl))) { fp@1831: return -EFAULT; fp@1831: } fp@1831: fp@1831: ec_soe_request_init(&request.req); fp@1837: ec_soe_request_set_idn(&request.req, ioctl.idn); fp@1831: ec_soe_request_read(&request.req); fp@1831: fp@1831: if (down_interruptible(&master->master_sem)) fp@1831: return -EINTR; fp@1831: fp@1831: if (!(request.slave = ec_master_find_slave( fp@1837: master, 0, ioctl.slave_position))) { fp@1831: up(&master->master_sem); fp@1831: ec_soe_request_clear(&request.req); fp@1837: EC_ERR("Slave %u does not exist!\n", ioctl.slave_position); fp@1831: return -EINVAL; fp@1831: } fp@1831: fp@1831: // schedule request. fp@1831: list_add_tail(&request.list, &request.slave->soe_requests); fp@1831: fp@1831: up(&master->master_sem); fp@1831: fp@1831: if (master->debug_level) { fp@1831: EC_DBG("Scheduled SoE read request on slave %u.\n", fp@1831: request.slave->ring_position); fp@1831: } fp@1831: fp@1831: // wait for processing through FSM fp@1831: if (wait_event_interruptible(request.slave->soe_queue, fp@1831: request.req.state != EC_INT_REQUEST_QUEUED)) { fp@1831: // interrupted by signal fp@1831: down(&master->master_sem); fp@1831: if (request.req.state == EC_INT_REQUEST_QUEUED) { fp@1831: list_del(&request.list); fp@1831: up(&master->master_sem); fp@1831: ec_soe_request_clear(&request.req); fp@1831: return -EINTR; fp@1831: } fp@1831: // request already processing: interrupt not possible. fp@1831: up(&master->master_sem); fp@1831: } fp@1831: fp@1831: // wait until master FSM has finished processing fp@1831: wait_event(request.slave->soe_queue, fp@1831: request.req.state != EC_INT_REQUEST_BUSY); fp@1831: fp@1837: ioctl.error_code = request.req.error_code; fp@1831: fp@1831: if (master->debug_level) { fp@1831: EC_DBG("Read %zd bytes via SoE.\n", request.req.data_size); fp@1831: } fp@1831: fp@1831: if (request.req.state != EC_INT_REQUEST_SUCCESS) { fp@1837: ioctl.data_size = 0; fp@1831: retval = -EIO; fp@1831: } else { fp@1837: if (request.req.data_size > ioctl.mem_size) { fp@1831: EC_ERR("Buffer too small.\n"); fp@1831: ec_soe_request_clear(&request.req); fp@1831: return -EOVERFLOW; fp@1831: } fp@1837: ioctl.data_size = request.req.data_size; fp@1837: if (copy_to_user((void __user *) ioctl.data, fp@1837: request.req.data, ioctl.data_size)) { fp@1831: ec_soe_request_clear(&request.req); fp@1831: return -EFAULT; fp@1831: } fp@1831: retval = 0; fp@1831: } fp@1831: fp@1837: if (__copy_to_user((void __user *) arg, &ioctl, sizeof(ioctl))) { fp@1831: retval = -EFAULT; fp@1831: } fp@1831: fp@1831: if (master->debug_level) fp@1831: EC_DBG("SoE read request finished on slave %u.\n", fp@1831: request.slave->ring_position); fp@1831: fp@1831: ec_soe_request_clear(&request.req); fp@1831: fp@1831: return retval; fp@1831: } fp@1831: fp@1831: /*****************************************************************************/ fp@1831: fp@1831: /** Write an IDN to a slave via SoE. fp@1831: */ fp@1831: int ec_cdev_ioctl_slave_soe_write( fp@1831: ec_master_t *master, /**< EtherCAT master. */ fp@1831: unsigned long arg /**< ioctl() argument. */ fp@1831: ) fp@1831: { fp@1837: ec_ioctl_slave_soe_write_t ioctl; fp@1831: ec_master_soe_request_t request; fp@1831: int retval; fp@1831: fp@1837: if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl))) { fp@1831: return -EFAULT; fp@1831: } fp@1831: fp@1831: INIT_LIST_HEAD(&request.list); fp@1831: fp@1831: ec_soe_request_init(&request.req); fp@1837: ec_soe_request_set_idn(&request.req, ioctl.idn); fp@1837: fp@1837: if (ec_soe_request_alloc(&request.req, ioctl.data_size)) { fp@1831: ec_soe_request_clear(&request.req); fp@1831: return -ENOMEM; fp@1831: } fp@1831: if (copy_from_user(request.req.data, fp@1837: (void __user *) ioctl.data, ioctl.data_size)) { fp@1831: ec_soe_request_clear(&request.req); fp@1831: return -EFAULT; fp@1831: } fp@1837: request.req.data_size = ioctl.data_size; fp@1831: ec_soe_request_write(&request.req); fp@1831: fp@1831: if (down_interruptible(&master->master_sem)) fp@1831: return -EINTR; fp@1831: fp@1831: if (!(request.slave = ec_master_find_slave( fp@1837: master, 0, ioctl.slave_position))) { fp@1837: up(&master->master_sem); fp@1837: EC_ERR("Slave %u does not exist!\n", ioctl.slave_position); fp@1831: ec_soe_request_clear(&request.req); fp@1831: return -EINVAL; fp@1831: } fp@1831: fp@1831: if (master->debug_level) { fp@1831: EC_DBG("Scheduling SoE write request.\n"); fp@1831: } fp@1831: fp@1831: // schedule SoE write request. fp@1831: list_add_tail(&request.list, &request.slave->soe_requests); fp@1831: fp@1831: up(&master->master_sem); fp@1831: fp@1831: // wait for processing through FSM fp@1831: if (wait_event_interruptible(request.slave->soe_queue, fp@1831: request.req.state != EC_INT_REQUEST_QUEUED)) { fp@1831: // interrupted by signal fp@1831: down(&master->master_sem); fp@1831: if (request.req.state == EC_INT_REQUEST_QUEUED) { fp@1831: // abort request fp@1831: list_del(&request.list); fp@1831: up(&master->master_sem); fp@1831: ec_soe_request_clear(&request.req); fp@1831: return -EINTR; fp@1831: } fp@1831: up(&master->master_sem); fp@1831: } fp@1831: fp@1831: // wait until master FSM has finished processing fp@1831: wait_event(request.slave->soe_queue, fp@1831: request.req.state != EC_INT_REQUEST_BUSY); fp@1831: fp@1839: ioctl.error_code = request.req.error_code; fp@1831: retval = request.req.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; fp@1831: fp@1837: if (__copy_to_user((void __user *) arg, &ioctl, sizeof(ioctl))) { fp@1831: retval = -EFAULT; fp@1831: } fp@1831: fp@1831: ec_soe_request_clear(&request.req); fp@1831: fp@1831: if (master->debug_level) { fp@1831: EC_DBG("Finished SoE writing.\n"); fp@1507: } fp@1335: fp@1335: return retval; fp@1335: } fp@1335: fp@922: /****************************************************************************** fp@922: * File operations fp@922: *****************************************************************************/ fp@922: fp@1092: /** Called when the cdev is opened. fp@1092: */ fp@922: int eccdev_open(struct inode *inode, struct file *filp) fp@922: { fp@922: ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev); fp@1242: ec_cdev_priv_t *priv; fp@1242: fp@1242: priv = kmalloc(sizeof(ec_cdev_priv_t), GFP_KERNEL); fp@1242: if (!priv) { fp@1242: EC_ERR("Failed to allocate memory for private data structure.\n"); fp@1242: return -ENOMEM; fp@1242: } fp@1242: fp@1242: priv->cdev = cdev; fp@1242: priv->requested = 0; fp@1258: priv->process_data = NULL; fp@1258: priv->process_data_size = 0; fp@1242: fp@1242: filp->private_data = priv; fp@1397: fp@1397: #if DEBUG_IOCTL fp@1397: EC_DBG("File opened.\n"); fp@1397: #endif fp@922: return 0; fp@922: } fp@922: fp@922: /*****************************************************************************/ fp@922: fp@1092: /** Called when the cdev is closed. fp@1092: */ fp@922: int eccdev_release(struct inode *inode, struct file *filp) fp@922: { fp@1242: ec_cdev_priv_t *priv = (ec_cdev_priv_t *) filp->private_data; fp@1242: ec_master_t *master = priv->cdev->master; fp@1242: fp@1242: if (priv->requested) fp@1242: ecrt_release_master(master); fp@935: fp@1258: if (priv->process_data) fp@1258: vfree(priv->process_data); fp@1258: fp@1397: #if DEBUG_IOCTL fp@1397: EC_DBG("File closed.\n"); fp@1397: #endif fp@1397: fp@1242: kfree(priv); fp@922: return 0; fp@922: } fp@922: fp@922: /*****************************************************************************/ fp@922: fp@1092: /** Called when an ioctl() command is issued. fp@1092: */ fp@935: long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) fp@935: { fp@1242: ec_cdev_priv_t *priv = (ec_cdev_priv_t *) filp->private_data; fp@1242: ec_master_t *master = priv->cdev->master; fp@922: fp@1397: #if DEBUG_IOCTL fp@1397: EC_DBG("ioctl(filp = 0x%x, cmd = 0x%08x (0x%02x), arg = 0x%x)\n", fp@1397: (u32) filp, (u32) cmd, (u32) _IOC_NR(cmd), (u32) arg); fp@1397: #endif fp@935: fp@922: switch (cmd) { fp@1826: case EC_IOCTL_MODULE: fp@1826: return ec_cdev_ioctl_module(arg); fp@957: case EC_IOCTL_MASTER: fp@1079: return ec_cdev_ioctl_master(master, arg); fp@935: case EC_IOCTL_SLAVE: fp@1079: return ec_cdev_ioctl_slave(master, arg); fp@1079: case EC_IOCTL_SLAVE_SYNC: fp@1079: return ec_cdev_ioctl_slave_sync(master, arg); fp@1079: case EC_IOCTL_SLAVE_SYNC_PDO: fp@1079: return ec_cdev_ioctl_slave_sync_pdo(master, arg); fp@1079: case EC_IOCTL_SLAVE_SYNC_PDO_ENTRY: fp@1079: return ec_cdev_ioctl_slave_sync_pdo_entry(master, arg); fp@948: case EC_IOCTL_DOMAIN: fp@1079: return ec_cdev_ioctl_domain(master, arg); fp@950: case EC_IOCTL_DOMAIN_FMMU: fp@1079: return ec_cdev_ioctl_domain_fmmu(master, arg); fp@1079: case EC_IOCTL_DOMAIN_DATA: fp@1079: return ec_cdev_ioctl_domain_data(master, arg); fp@1079: case EC_IOCTL_MASTER_DEBUG: fp@972: if (!(filp->f_mode & FMODE_WRITE)) fp@972: return -EPERM; fp@1079: return ec_cdev_ioctl_master_debug(master, arg); fp@960: case EC_IOCTL_SLAVE_STATE: fp@1079: if (!(filp->f_mode & FMODE_WRITE)) fp@1079: return -EPERM; fp@1079: return ec_cdev_ioctl_slave_state(master, arg); fp@1079: case EC_IOCTL_SLAVE_SDO: fp@1079: return ec_cdev_ioctl_slave_sdo(master, arg); fp@1079: case EC_IOCTL_SLAVE_SDO_ENTRY: fp@1079: return ec_cdev_ioctl_slave_sdo_entry(master, arg); fp@1079: case EC_IOCTL_SLAVE_SDO_UPLOAD: fp@1079: return ec_cdev_ioctl_slave_sdo_upload(master, arg); fp@1079: case EC_IOCTL_SLAVE_SDO_DOWNLOAD: fp@1079: if (!(filp->f_mode & FMODE_WRITE)) fp@1079: return -EPERM; fp@1079: return ec_cdev_ioctl_slave_sdo_download(master, arg); fp@1079: case EC_IOCTL_SLAVE_SII_READ: fp@1079: return ec_cdev_ioctl_slave_sii_read(master, arg); fp@1079: case EC_IOCTL_SLAVE_SII_WRITE: fp@1079: if (!(filp->f_mode & FMODE_WRITE)) fp@1079: return -EPERM; fp@1079: return ec_cdev_ioctl_slave_sii_write(master, arg); fp@1388: case EC_IOCTL_SLAVE_REG_READ: fp@1388: return ec_cdev_ioctl_slave_reg_read(master, arg); fp@1388: case EC_IOCTL_SLAVE_REG_WRITE: fp@1200: if (!(filp->f_mode & FMODE_WRITE)) fp@1200: return -EPERM; fp@1388: return ec_cdev_ioctl_slave_reg_write(master, arg); fp@1335: case EC_IOCTL_SLAVE_FOE_READ: fp@1335: return ec_cdev_ioctl_slave_foe_read(master, arg); fp@1335: case EC_IOCTL_SLAVE_FOE_WRITE: fp@1335: if (!(filp->f_mode & FMODE_WRITE)) fp@1335: return -EPERM; fp@1335: return ec_cdev_ioctl_slave_foe_write(master, arg); fp@1831: case EC_IOCTL_SLAVE_SOE_READ: fp@1831: return ec_cdev_ioctl_slave_soe_read(master, arg); fp@1831: case EC_IOCTL_SLAVE_SOE_WRITE: fp@1831: if (!(filp->f_mode & FMODE_WRITE)) fp@1831: return -EPERM; fp@1831: return ec_cdev_ioctl_slave_soe_write(master, arg); fp@990: case EC_IOCTL_CONFIG: fp@1079: return ec_cdev_ioctl_config(master, arg); fp@990: case EC_IOCTL_CONFIG_PDO: fp@1079: return ec_cdev_ioctl_config_pdo(master, arg); fp@990: case EC_IOCTL_CONFIG_PDO_ENTRY: fp@1079: return ec_cdev_ioctl_config_pdo_entry(master, arg); fp@990: case EC_IOCTL_CONFIG_SDO: fp@1079: return ec_cdev_ioctl_config_sdo(master, arg); fp@1516: #ifdef EC_EOE fp@1485: case EC_IOCTL_EOE_HANDLER: fp@1485: return ec_cdev_ioctl_eoe_handler(master, arg); fp@1516: #endif fp@1242: case EC_IOCTL_REQUEST: fp@1242: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_request(master, arg, priv); fp@1244: case EC_IOCTL_CREATE_DOMAIN: fp@1244: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_create_domain(master, arg, priv); fp@1246: case EC_IOCTL_CREATE_SLAVE_CONFIG: fp@1246: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_create_slave_config(master, arg, priv); fp@1247: case EC_IOCTL_ACTIVATE: fp@1247: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_activate(master, arg, priv); fp@1531: case EC_IOCTL_DEACTIVATE: fp@1531: if (!(filp->f_mode & FMODE_WRITE)) fp@1531: return -EPERM; fp@1531: return ec_cdev_ioctl_deactivate(master, arg, priv); fp@1247: case EC_IOCTL_SEND: fp@1247: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_send(master, arg, priv); fp@1247: case EC_IOCTL_RECEIVE: fp@1247: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_receive(master, arg, priv); fp@1259: case EC_IOCTL_MASTER_STATE: fp@1507: return ec_cdev_ioctl_master_state(master, arg, priv); fp@1454: case EC_IOCTL_APP_TIME: fp@1454: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_app_time(master, arg, priv); fp@1413: case EC_IOCTL_SYNC_REF: fp@1413: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_sync_ref(master, arg, priv); fp@1413: case EC_IOCTL_SYNC_SLAVES: fp@1413: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_sync_slaves(master, arg, priv); fp@1535: case EC_IOCTL_SYNC_MON_QUEUE: fp@1535: if (!(filp->f_mode & FMODE_WRITE)) fp@1535: return -EPERM; fp@1535: return ec_cdev_ioctl_sync_mon_queue(master, arg, priv); fp@1535: case EC_IOCTL_SYNC_MON_PROCESS: fp@1535: if (!(filp->f_mode & FMODE_WRITE)) fp@1535: return -EPERM; fp@1535: return ec_cdev_ioctl_sync_mon_process(master, arg, priv); fp@1255: case EC_IOCTL_SC_SYNC: fp@1255: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_sc_sync(master, arg, priv); fp@1509: case EC_IOCTL_SC_WATCHDOG: fp@1509: if (!(filp->f_mode & FMODE_WRITE)) fp@1509: return -EPERM; fp@1509: return ec_cdev_ioctl_sc_watchdog(master, arg, priv); fp@1255: case EC_IOCTL_SC_ADD_PDO: fp@1255: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_sc_add_pdo(master, arg, priv); fp@1255: case EC_IOCTL_SC_CLEAR_PDOS: fp@1255: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_sc_clear_pdos(master, arg, priv); fp@1255: case EC_IOCTL_SC_ADD_ENTRY: fp@1255: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_sc_add_entry(master, arg, priv); fp@1255: case EC_IOCTL_SC_CLEAR_ENTRIES: fp@1255: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_sc_clear_entries(master, arg, priv); fp@1255: case EC_IOCTL_SC_REG_PDO_ENTRY: fp@1255: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_sc_reg_pdo_entry(master, arg, priv); fp@1448: case EC_IOCTL_SC_DC: fp@1413: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_sc_dc(master, arg, priv); fp@1255: case EC_IOCTL_SC_SDO: fp@1255: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_sc_sdo(master, arg, priv); fp@1352: case EC_IOCTL_SC_SDO_REQUEST: fp@1352: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_sc_create_sdo_request(master, arg, priv); fp@1264: case EC_IOCTL_SC_VOE: fp@1264: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_sc_create_voe_handler(master, arg, priv); fp@1259: case EC_IOCTL_SC_STATE: fp@1507: return ec_cdev_ioctl_sc_state(master, arg, priv); fp@1258: case EC_IOCTL_DOMAIN_OFFSET: fp@1507: return ec_cdev_ioctl_domain_offset(master, arg, priv); fp@1258: case EC_IOCTL_DOMAIN_PROCESS: fp@1258: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_domain_process(master, arg, priv); fp@1258: case EC_IOCTL_DOMAIN_QUEUE: fp@1258: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_domain_queue(master, arg, priv); fp@1259: case EC_IOCTL_DOMAIN_STATE: fp@1507: return ec_cdev_ioctl_domain_state(master, arg, priv); fp@1352: case EC_IOCTL_SDO_REQUEST_TIMEOUT: fp@1352: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_sdo_request_timeout(master, arg, priv); fp@1352: case EC_IOCTL_SDO_REQUEST_STATE: fp@1507: return ec_cdev_ioctl_sdo_request_state(master, arg, priv); fp@1352: case EC_IOCTL_SDO_REQUEST_READ: fp@1352: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_sdo_request_read(master, arg, priv); fp@1352: case EC_IOCTL_SDO_REQUEST_WRITE: fp@1352: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_sdo_request_write(master, arg, priv); fp@1352: case EC_IOCTL_SDO_REQUEST_DATA: fp@1507: return ec_cdev_ioctl_sdo_request_data(master, arg, priv); fp@1264: case EC_IOCTL_VOE_SEND_HEADER: fp@1264: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_voe_send_header(master, arg, priv); fp@1264: case EC_IOCTL_VOE_REC_HEADER: fp@1507: return ec_cdev_ioctl_voe_rec_header(master, arg, priv); fp@1264: case EC_IOCTL_VOE_READ: fp@1264: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_voe_read(master, arg, priv); fp@1314: case EC_IOCTL_VOE_READ_NOSYNC: fp@1314: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_voe_read_nosync(master, arg, priv); fp@1264: case EC_IOCTL_VOE_WRITE: fp@1264: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_voe_write(master, arg, priv); fp@1264: case EC_IOCTL_VOE_EXEC: fp@1264: if (!(filp->f_mode & FMODE_WRITE)) fp@1507: return -EPERM; fp@1507: return ec_cdev_ioctl_voe_exec(master, arg, priv); fp@1264: case EC_IOCTL_VOE_DATA: fp@1507: return ec_cdev_ioctl_voe_data(master, arg, priv); fp@1804: case EC_IOCTL_SET_SEND_INTERVAL: fp@1804: if (!(filp->f_mode & FMODE_WRITE)) fp@1804: return -EPERM; fp@1804: return ec_cdev_ioctl_set_send_interval(master,arg,priv); fp@922: default: fp@1079: return -ENOTTY; fp@1079: } fp@1079: } fp@1079: fp@1079: /*****************************************************************************/ fp@1258: fp@1268: /** Memory-map callback for the EtherCAT character device. fp@1268: * fp@1268: * The actual mapping will be done in the eccdev_vma_nopage() callback of the fp@1268: * virtual memory area. fp@1268: */ fp@1258: int eccdev_mmap( fp@1258: struct file *filp, fp@1258: struct vm_area_struct *vma fp@1258: ) fp@1258: { fp@1258: ec_cdev_priv_t *priv = (ec_cdev_priv_t *) filp->private_data; fp@1258: fp@1258: if (priv->cdev->master->debug_level) fp@1258: EC_DBG("mmap()\n"); fp@1258: fp@1258: vma->vm_ops = &eccdev_vm_ops; fp@1258: vma->vm_flags |= VM_RESERVED; /* Pages will not be swapped out */ fp@1258: vma->vm_private_data = priv; fp@1258: fp@1258: return 0; fp@1258: } fp@1258: fp@1258: /*****************************************************************************/ fp@1258: fp@1272: #if LINUX_VERSION_CODE >= PAGE_FAULT_VERSION fp@1272: fp@1268: /** Page fault callback for a virtual memory area. fp@1268: * fp@1268: * Called at the first access on a virtual-memory area retrieved with fp@1268: * ecdev_mmap(). fp@1268: */ fp@1272: static int eccdev_vma_fault( fp@1272: struct vm_area_struct *vma, /**< Virtual memory area. */ fp@1272: struct vm_fault *vmf /**< Fault data. */ fp@1272: ) fp@1272: { fp@1284: unsigned long offset = vmf->pgoff << PAGE_SHIFT; fp@1284: ec_cdev_priv_t *priv = (ec_cdev_priv_t *) vma->vm_private_data; fp@1272: struct page *page; fp@1284: fp@1284: if (offset >= priv->process_data_size) fp@1272: return VM_FAULT_SIGBUS; fp@1272: fp@1284: page = vmalloc_to_page(priv->process_data + offset); fp@1284: if (!page) fp@1284: return VM_FAULT_SIGBUS; fp@1272: fp@1272: get_page(page); fp@1272: vmf->page = page; fp@1284: fp@1284: if (priv->cdev->master->debug_level) fp@1284: EC_DBG("Vma fault, virtual_address = %p, offset = %lu, page = %p\n", fp@1284: vmf->virtual_address, offset, page); fp@1284: fp@1272: return 0; fp@1272: } fp@1272: fp@1272: #else fp@1272: fp@1272: /** Nopage callback for a virtual memory area. fp@1272: * fp@1272: * Called at the first access on a virtual-memory area retrieved with fp@1272: * ecdev_mmap(). fp@1272: */ fp@1258: struct page *eccdev_vma_nopage( fp@1268: struct vm_area_struct *vma, /**< Virtual memory area initialized by fp@1268: the kernel. */ fp@1268: unsigned long address, /**< Requested virtual address. */ fp@1268: int *type /**< Type output parameter. */ fp@1258: ) fp@1258: { fp@1258: unsigned long offset; fp@1258: struct page *page = NOPAGE_SIGBUS; fp@1258: ec_cdev_priv_t *priv = (ec_cdev_priv_t *) vma->vm_private_data; fp@1258: fp@1258: offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); fp@1258: fp@1258: if (offset >= priv->process_data_size) fp@1258: return NOPAGE_SIGBUS; fp@1258: fp@1258: page = vmalloc_to_page(priv->process_data + offset); fp@1258: fp@1258: if (priv->cdev->master->debug_level) fp@1258: EC_DBG("Nopage fault vma, address = %#lx, offset = %#lx, page = %p\n", fp@1258: address, offset, page); fp@1258: fp@1258: get_page(page); fp@1258: if (type) fp@1258: *type = VM_FAULT_MINOR; fp@1258: fp@1258: return page; fp@1258: } fp@1258: fp@1272: #endif fp@1272: fp@1272: /*****************************************************************************/