master/ioctl.c
branchstable-1.5
changeset 2433 3bdd7a747fae
child 2434 fa52128477f6
equal deleted inserted replaced
2432:f4313f5aba88 2433:3bdd7a747fae
       
     1 /******************************************************************************
       
     2  *
       
     3  *  $Id$
       
     4  *
       
     5  *  Copyright (C) 2006-2012  Florian Pose, Ingenieurgemeinschaft IgH
       
     6  *
       
     7  *  This file is part of the IgH EtherCAT Master.
       
     8  *
       
     9  *  The IgH EtherCAT Master is free software; you can redistribute it and/or
       
    10  *  modify it under the terms of the GNU General Public License version 2, as
       
    11  *  published by the Free Software Foundation.
       
    12  *
       
    13  *  The IgH EtherCAT Master is distributed in the hope that it will be useful,
       
    14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
       
    16  *  Public License for more details.
       
    17  *
       
    18  *  You should have received a copy of the GNU General Public License along
       
    19  *  with the IgH EtherCAT Master; if not, write to the Free Software
       
    20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       
    21  *
       
    22  *  ---
       
    23  *
       
    24  *  The license mentioned above concerns the source code only. Using the
       
    25  *  EtherCAT technology and brand is only permitted in compliance with the
       
    26  *  industrial property and similar rights of Beckhoff Automation GmbH.
       
    27  *
       
    28  *****************************************************************************/
       
    29 
       
    30 /**
       
    31    \file
       
    32    EtherCAT master character device.
       
    33 */
       
    34 
       
    35 /*****************************************************************************/
       
    36 
       
    37 #include <linux/module.h>
       
    38 
       
    39 #include "master.h"
       
    40 #include "slave_config.h"
       
    41 #include "voe_handler.h"
       
    42 #include "ethernet.h"
       
    43 #include "ioctl.h"
       
    44 
       
    45 /** Set to 1 to enable ioctl() latency tracing.
       
    46  *
       
    47  * Requires CPU timestamp counter!
       
    48  */
       
    49 #define DEBUG_LATENCY 0
       
    50 
       
    51 /*****************************************************************************/
       
    52 
       
    53 /** Copies a string to an ioctl structure.
       
    54  */
       
    55 static void ec_ioctl_strcpy(
       
    56         char *target, /**< Target. */
       
    57         const char *source /**< Source. */
       
    58         )
       
    59 {
       
    60     if (source) {
       
    61         strncpy(target, source, EC_IOCTL_STRING_SIZE);
       
    62         target[EC_IOCTL_STRING_SIZE - 1] = 0;
       
    63     } else {
       
    64         target[0] = 0;
       
    65     }
       
    66 }
       
    67 
       
    68 /*****************************************************************************/
       
    69 
       
    70 /** Get module information.
       
    71  */
       
    72 static int ec_ioctl_module(
       
    73         void *arg /**< Userspace address to store the results. */
       
    74         )
       
    75 {
       
    76     ec_ioctl_module_t data;
       
    77 
       
    78     data.ioctl_version_magic = EC_IOCTL_VERSION_MAGIC;
       
    79     data.master_count = ec_master_count();
       
    80 
       
    81     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
    82         return -EFAULT;
       
    83 
       
    84     return 0;
       
    85 }
       
    86 
       
    87 /*****************************************************************************/
       
    88 
       
    89 /** Get master information.
       
    90  */
       
    91 static int ec_ioctl_master(
       
    92         ec_master_t *master, /**< EtherCAT master. */
       
    93         void *arg /**< Userspace address to store the results. */
       
    94         )
       
    95 {
       
    96     ec_ioctl_master_t data;
       
    97     unsigned int i, j;
       
    98 
       
    99     if (down_interruptible(&master->master_sem))
       
   100         return -EINTR;
       
   101 
       
   102     data.slave_count = master->slave_count;
       
   103     data.config_count = ec_master_config_count(master);
       
   104     data.domain_count = ec_master_domain_count(master);
       
   105 #ifdef EC_EOE
       
   106     data.eoe_handler_count = ec_master_eoe_handler_count(master);
       
   107 #endif
       
   108     data.phase = (uint8_t) master->phase;
       
   109     data.active = (uint8_t) master->active;
       
   110     data.scan_busy = master->scan_busy;
       
   111 
       
   112     up(&master->master_sem);
       
   113 
       
   114     if (down_interruptible(&master->device_sem))
       
   115         return -EINTR;
       
   116 
       
   117     for (i = 0; i < EC_NUM_DEVICES; i++) {
       
   118         ec_device_t *device = &master->devices[i];
       
   119 
       
   120         if (device->dev) {
       
   121             memcpy(data.devices[i].address,
       
   122                     device->dev->dev_addr, ETH_ALEN);
       
   123         } else {
       
   124             memcpy(data.devices[i].address, master->macs[i], ETH_ALEN);
       
   125         }
       
   126         data.devices[i].attached = device->dev ? 1 : 0;
       
   127         data.devices[i].link_state = device->link_state ? 1 : 0;
       
   128         data.devices[i].tx_count = device->tx_count;
       
   129         data.devices[i].rx_count = device->rx_count;
       
   130         data.devices[i].tx_bytes = device->tx_bytes;
       
   131         data.devices[i].rx_bytes = device->rx_bytes;
       
   132         data.devices[i].tx_errors = device->tx_errors;
       
   133         for (j = 0; j < EC_RATE_COUNT; j++) {
       
   134             data.devices[i].tx_frame_rates[j] =
       
   135                 device->tx_frame_rates[j];
       
   136             data.devices[i].rx_frame_rates[j] =
       
   137                 device->rx_frame_rates[j];
       
   138             data.devices[i].tx_byte_rates[j] =
       
   139                 device->tx_byte_rates[j];
       
   140             data.devices[i].rx_byte_rates[j] =
       
   141                 device->rx_byte_rates[j];
       
   142         }
       
   143     }
       
   144 
       
   145     data.tx_count = master->device_stats.tx_count;
       
   146     data.rx_count = master->device_stats.rx_count;
       
   147     data.tx_bytes = master->device_stats.tx_bytes;
       
   148     data.rx_bytes = master->device_stats.rx_bytes;
       
   149     for (i = 0; i < EC_RATE_COUNT; i++) {
       
   150         data.tx_frame_rates[i] =
       
   151             master->device_stats.tx_frame_rates[i];
       
   152         data.rx_frame_rates[i] =
       
   153             master->device_stats.rx_frame_rates[i];
       
   154         data.tx_byte_rates[i] =
       
   155             master->device_stats.tx_byte_rates[i];
       
   156         data.rx_byte_rates[i] =
       
   157             master->device_stats.rx_byte_rates[i];
       
   158         data.loss_rates[i] =
       
   159             master->device_stats.loss_rates[i];
       
   160     }
       
   161 
       
   162     up(&master->device_sem);
       
   163 
       
   164     data.app_time = master->app_time;
       
   165     data.ref_clock =
       
   166         master->dc_ref_clock ? master->dc_ref_clock->ring_position : 0xffff;
       
   167 
       
   168     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
   169         return -EFAULT;
       
   170 
       
   171     return 0;
       
   172 }
       
   173 
       
   174 /*****************************************************************************/
       
   175 
       
   176 /** Get slave information.
       
   177  */
       
   178 static int ec_ioctl_slave(
       
   179         ec_master_t *master, /**< EtherCAT master. */
       
   180         void *arg /**< Userspace address to store the results. */
       
   181         )
       
   182 {
       
   183     ec_ioctl_slave_t data;
       
   184     const ec_slave_t *slave;
       
   185     int i;
       
   186 
       
   187     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
   188         return -EFAULT;
       
   189     }
       
   190 
       
   191     if (down_interruptible(&master->master_sem))
       
   192         return -EINTR;
       
   193 
       
   194     if (!(slave = ec_master_find_slave_const(
       
   195                     master, 0, data.position))) {
       
   196         up(&master->master_sem);
       
   197         EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.position);
       
   198         return -EINVAL;
       
   199     }
       
   200 
       
   201     data.device_index = slave->device_index;
       
   202     data.vendor_id = slave->sii.vendor_id;
       
   203     data.product_code = slave->sii.product_code;
       
   204     data.revision_number = slave->sii.revision_number;
       
   205     data.serial_number = slave->sii.serial_number;
       
   206     data.alias = slave->effective_alias;
       
   207     data.boot_rx_mailbox_offset = slave->sii.boot_rx_mailbox_offset;
       
   208     data.boot_rx_mailbox_size = slave->sii.boot_rx_mailbox_size;
       
   209     data.boot_tx_mailbox_offset = slave->sii.boot_tx_mailbox_offset;
       
   210     data.boot_tx_mailbox_size = slave->sii.boot_tx_mailbox_size;
       
   211     data.std_rx_mailbox_offset = slave->sii.std_rx_mailbox_offset;
       
   212     data.std_rx_mailbox_size = slave->sii.std_rx_mailbox_size;
       
   213     data.std_tx_mailbox_offset = slave->sii.std_tx_mailbox_offset;
       
   214     data.std_tx_mailbox_size = slave->sii.std_tx_mailbox_size;
       
   215     data.mailbox_protocols = slave->sii.mailbox_protocols;
       
   216     data.has_general_category = slave->sii.has_general;
       
   217     data.coe_details = slave->sii.coe_details;
       
   218     data.general_flags = slave->sii.general_flags;
       
   219     data.current_on_ebus = slave->sii.current_on_ebus;
       
   220     for (i = 0; i < EC_MAX_PORTS; i++) {
       
   221         data.ports[i].desc = slave->ports[i].desc;
       
   222         data.ports[i].link.link_up = slave->ports[i].link.link_up;
       
   223         data.ports[i].link.loop_closed = slave->ports[i].link.loop_closed;
       
   224         data.ports[i].link.signal_detected =
       
   225             slave->ports[i].link.signal_detected;
       
   226         data.ports[i].receive_time = slave->ports[i].receive_time;
       
   227         if (slave->ports[i].next_slave) {
       
   228             data.ports[i].next_slave =
       
   229                 slave->ports[i].next_slave->ring_position;
       
   230         } else {
       
   231             data.ports[i].next_slave = 0xffff;
       
   232         }
       
   233         data.ports[i].delay_to_next_dc = slave->ports[i].delay_to_next_dc;
       
   234     }
       
   235     data.fmmu_bit = slave->base_fmmu_bit_operation;
       
   236     data.dc_supported = slave->base_dc_supported;
       
   237     data.dc_range = slave->base_dc_range;
       
   238     data.has_dc_system_time = slave->has_dc_system_time;
       
   239     data.transmission_delay = slave->transmission_delay;
       
   240     data.al_state = slave->current_state;
       
   241     data.error_flag = slave->error_flag;
       
   242 
       
   243     data.sync_count = slave->sii.sync_count;
       
   244     data.sdo_count = ec_slave_sdo_count(slave);
       
   245     data.sii_nwords = slave->sii_nwords;
       
   246     ec_ioctl_strcpy(data.group, slave->sii.group);
       
   247     ec_ioctl_strcpy(data.image, slave->sii.image);
       
   248     ec_ioctl_strcpy(data.order, slave->sii.order);
       
   249     ec_ioctl_strcpy(data.name, slave->sii.name);
       
   250 
       
   251     up(&master->master_sem);
       
   252 
       
   253     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
   254         return -EFAULT;
       
   255 
       
   256     return 0;
       
   257 }
       
   258 
       
   259 /*****************************************************************************/
       
   260 
       
   261 /** Get slave sync manager information.
       
   262  */
       
   263 static int ec_ioctl_slave_sync(
       
   264         ec_master_t *master, /**< EtherCAT master. */
       
   265         void *arg /**< Userspace address to store the results. */
       
   266         )
       
   267 {
       
   268     ec_ioctl_slave_sync_t data;
       
   269     const ec_slave_t *slave;
       
   270     const ec_sync_t *sync;
       
   271 
       
   272     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
   273         return -EFAULT;
       
   274     }
       
   275 
       
   276     if (down_interruptible(&master->master_sem))
       
   277         return -EINTR;
       
   278 
       
   279     if (!(slave = ec_master_find_slave_const(
       
   280                     master, 0, data.slave_position))) {
       
   281         up(&master->master_sem);
       
   282         EC_MASTER_ERR(master, "Slave %u does not exist!\n",
       
   283                 data.slave_position);
       
   284         return -EINVAL;
       
   285     }
       
   286 
       
   287     if (data.sync_index >= slave->sii.sync_count) {
       
   288         up(&master->master_sem);
       
   289         EC_SLAVE_ERR(slave, "Sync manager %u does not exist!\n",
       
   290                 data.sync_index);
       
   291         return -EINVAL;
       
   292     }
       
   293 
       
   294     sync = &slave->sii.syncs[data.sync_index];
       
   295 
       
   296     data.physical_start_address = sync->physical_start_address;
       
   297     data.default_size = sync->default_length;
       
   298     data.control_register = sync->control_register;
       
   299     data.enable = sync->enable;
       
   300     data.pdo_count = ec_pdo_list_count(&sync->pdos);
       
   301 
       
   302     up(&master->master_sem);
       
   303 
       
   304     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
   305         return -EFAULT;
       
   306 
       
   307     return 0;
       
   308 }
       
   309 
       
   310 /*****************************************************************************/
       
   311 
       
   312 /** Get slave sync manager PDO information.
       
   313  */
       
   314 static int ec_ioctl_slave_sync_pdo(
       
   315         ec_master_t *master, /**< EtherCAT master. */
       
   316         void *arg /**< Userspace address to store the results. */
       
   317         )
       
   318 {
       
   319     ec_ioctl_slave_sync_pdo_t data;
       
   320     const ec_slave_t *slave;
       
   321     const ec_sync_t *sync;
       
   322     const ec_pdo_t *pdo;
       
   323 
       
   324     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
   325         return -EFAULT;
       
   326     }
       
   327 
       
   328     if (down_interruptible(&master->master_sem))
       
   329         return -EINTR;
       
   330 
       
   331     if (!(slave = ec_master_find_slave_const(
       
   332                     master, 0, data.slave_position))) {
       
   333         up(&master->master_sem);
       
   334         EC_MASTER_ERR(master, "Slave %u does not exist!\n",
       
   335                 data.slave_position);
       
   336         return -EINVAL;
       
   337     }
       
   338 
       
   339     if (data.sync_index >= slave->sii.sync_count) {
       
   340         up(&master->master_sem);
       
   341         EC_SLAVE_ERR(slave, "Sync manager %u does not exist!\n",
       
   342                 data.sync_index);
       
   343         return -EINVAL;
       
   344     }
       
   345 
       
   346     sync = &slave->sii.syncs[data.sync_index];
       
   347     if (!(pdo = ec_pdo_list_find_pdo_by_pos_const(
       
   348                     &sync->pdos, data.pdo_pos))) {
       
   349         up(&master->master_sem);
       
   350         EC_SLAVE_ERR(slave, "Sync manager %u does not contain a PDO with "
       
   351                 "position %u!\n", data.sync_index, data.pdo_pos);
       
   352         return -EINVAL;
       
   353     }
       
   354 
       
   355     data.index = pdo->index;
       
   356     data.entry_count = ec_pdo_entry_count(pdo);
       
   357     ec_ioctl_strcpy(data.name, pdo->name);
       
   358 
       
   359     up(&master->master_sem);
       
   360 
       
   361     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
   362         return -EFAULT;
       
   363 
       
   364     return 0;
       
   365 }
       
   366 
       
   367 /*****************************************************************************/
       
   368 
       
   369 /** Get slave sync manager PDO entry information.
       
   370  */
       
   371 static int ec_ioctl_slave_sync_pdo_entry(
       
   372         ec_master_t *master, /**< EtherCAT master. */
       
   373         void *arg /**< Userspace address to store the results. */
       
   374         )
       
   375 {
       
   376     ec_ioctl_slave_sync_pdo_entry_t data;
       
   377     const ec_slave_t *slave;
       
   378     const ec_sync_t *sync;
       
   379     const ec_pdo_t *pdo;
       
   380     const ec_pdo_entry_t *entry;
       
   381 
       
   382     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
   383         return -EFAULT;
       
   384     }
       
   385 
       
   386     if (down_interruptible(&master->master_sem))
       
   387         return -EINTR;
       
   388 
       
   389     if (!(slave = ec_master_find_slave_const(
       
   390                     master, 0, data.slave_position))) {
       
   391         up(&master->master_sem);
       
   392         EC_MASTER_ERR(master, "Slave %u does not exist!\n",
       
   393                 data.slave_position);
       
   394         return -EINVAL;
       
   395     }
       
   396 
       
   397     if (data.sync_index >= slave->sii.sync_count) {
       
   398         up(&master->master_sem);
       
   399         EC_SLAVE_ERR(slave, "Sync manager %u does not exist!\n",
       
   400                 data.sync_index);
       
   401         return -EINVAL;
       
   402     }
       
   403 
       
   404     sync = &slave->sii.syncs[data.sync_index];
       
   405     if (!(pdo = ec_pdo_list_find_pdo_by_pos_const(
       
   406                     &sync->pdos, data.pdo_pos))) {
       
   407         up(&master->master_sem);
       
   408         EC_SLAVE_ERR(slave, "Sync manager %u does not contain a PDO with "
       
   409                 "position %u!\n", data.sync_index, data.pdo_pos);
       
   410         return -EINVAL;
       
   411     }
       
   412 
       
   413     if (!(entry = ec_pdo_find_entry_by_pos_const(
       
   414                     pdo, data.entry_pos))) {
       
   415         up(&master->master_sem);
       
   416         EC_SLAVE_ERR(slave, "PDO 0x%04X does not contain an entry with "
       
   417                 "position %u!\n", data.pdo_pos, data.entry_pos);
       
   418         return -EINVAL;
       
   419     }
       
   420 
       
   421     data.index = entry->index;
       
   422     data.subindex = entry->subindex;
       
   423     data.bit_length = entry->bit_length;
       
   424     ec_ioctl_strcpy(data.name, entry->name);
       
   425 
       
   426     up(&master->master_sem);
       
   427 
       
   428     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
   429         return -EFAULT;
       
   430 
       
   431     return 0;
       
   432 }
       
   433 
       
   434 /*****************************************************************************/
       
   435 
       
   436 /** Get domain information.
       
   437  */
       
   438 static int ec_ioctl_domain(
       
   439         ec_master_t *master, /**< EtherCAT master. */
       
   440         void *arg /**< Userspace address to store the results. */
       
   441         )
       
   442 {
       
   443     ec_ioctl_domain_t data;
       
   444     const ec_domain_t *domain;
       
   445     unsigned int dev_idx;
       
   446 
       
   447     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
   448         return -EFAULT;
       
   449     }
       
   450 
       
   451     if (down_interruptible(&master->master_sem))
       
   452         return -EINTR;
       
   453 
       
   454     if (!(domain = ec_master_find_domain_const(master, data.index))) {
       
   455         up(&master->master_sem);
       
   456         EC_MASTER_ERR(master, "Domain %u does not exist!\n", data.index);
       
   457         return -EINVAL;
       
   458     }
       
   459 
       
   460     data.data_size = domain->data_size;
       
   461     data.logical_base_address = domain->logical_base_address;
       
   462     for (dev_idx = 0; dev_idx < EC_NUM_DEVICES; dev_idx++) {
       
   463         data.working_counter[dev_idx] = domain->working_counter[dev_idx];
       
   464     }
       
   465     data.expected_working_counter = domain->expected_working_counter;
       
   466     data.fmmu_count = ec_domain_fmmu_count(domain);
       
   467 
       
   468     up(&master->master_sem);
       
   469 
       
   470     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
   471         return -EFAULT;
       
   472 
       
   473     return 0;
       
   474 }
       
   475 
       
   476 /*****************************************************************************/
       
   477 
       
   478 /** Get domain FMMU information.
       
   479  */
       
   480 static int ec_ioctl_domain_fmmu(
       
   481         ec_master_t *master, /**< EtherCAT master. */
       
   482         void *arg /**< Userspace address to store the results. */
       
   483         )
       
   484 {
       
   485     ec_ioctl_domain_fmmu_t data;
       
   486     const ec_domain_t *domain;
       
   487     const ec_fmmu_config_t *fmmu;
       
   488 
       
   489     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
   490         return -EFAULT;
       
   491     }
       
   492 
       
   493     if (down_interruptible(&master->master_sem))
       
   494         return -EINTR;
       
   495 
       
   496     if (!(domain = ec_master_find_domain_const(master, data.domain_index))) {
       
   497         up(&master->master_sem);
       
   498         EC_MASTER_ERR(master, "Domain %u does not exist!\n",
       
   499                 data.domain_index);
       
   500         return -EINVAL;
       
   501     }
       
   502 
       
   503     if (!(fmmu = ec_domain_find_fmmu(domain, data.fmmu_index))) {
       
   504         up(&master->master_sem);
       
   505         EC_MASTER_ERR(master, "Domain %u has less than %u"
       
   506                 " fmmu configurations.\n",
       
   507                 data.domain_index, data.fmmu_index + 1);
       
   508         return -EINVAL;
       
   509     }
       
   510 
       
   511     data.slave_config_alias = fmmu->sc->alias;
       
   512     data.slave_config_position = fmmu->sc->position;
       
   513     data.sync_index = fmmu->sync_index;
       
   514     data.dir = fmmu->dir;
       
   515     data.logical_address = fmmu->logical_start_address;
       
   516     data.data_size = fmmu->data_size;
       
   517 
       
   518     up(&master->master_sem);
       
   519 
       
   520     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
   521         return -EFAULT;
       
   522 
       
   523     return 0;
       
   524 }
       
   525 
       
   526 /*****************************************************************************/
       
   527 
       
   528 /** Get domain data.
       
   529  */
       
   530 static int ec_ioctl_domain_data(
       
   531         ec_master_t *master, /**< EtherCAT master. */
       
   532         void *arg /**< Userspace address to store the results. */
       
   533         )
       
   534 {
       
   535     ec_ioctl_domain_data_t data;
       
   536     const ec_domain_t *domain;
       
   537 
       
   538     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
   539         return -EFAULT;
       
   540     }
       
   541 
       
   542     if (down_interruptible(&master->master_sem))
       
   543         return -EINTR;
       
   544 
       
   545     if (!(domain = ec_master_find_domain_const(master, data.domain_index))) {
       
   546         up(&master->master_sem);
       
   547         EC_MASTER_ERR(master, "Domain %u does not exist!\n",
       
   548                 data.domain_index);
       
   549         return -EINVAL;
       
   550     }
       
   551 
       
   552     if (domain->data_size != data.data_size) {
       
   553         up(&master->master_sem);
       
   554         EC_MASTER_ERR(master, "Data size mismatch %u/%zu!\n",
       
   555                 data.data_size, domain->data_size);
       
   556         return -EFAULT;
       
   557     }
       
   558 
       
   559     if (copy_to_user((void __user *) data.target, domain->data,
       
   560                 domain->data_size)) {
       
   561         up(&master->master_sem);
       
   562         return -EFAULT;
       
   563     }
       
   564 
       
   565     up(&master->master_sem);
       
   566     return 0;
       
   567 }
       
   568 
       
   569 /*****************************************************************************/
       
   570 
       
   571 /** Set master debug level.
       
   572  */
       
   573 static int ec_ioctl_master_debug(
       
   574         ec_master_t *master, /**< EtherCAT master. */
       
   575         void *arg /**< ioctl() argument. */
       
   576         )
       
   577 {
       
   578     return ec_master_debug_level(master, (unsigned int) arg);
       
   579 }
       
   580 
       
   581 /*****************************************************************************/
       
   582 
       
   583 /** Issue a bus scan.
       
   584  */
       
   585 static int ec_ioctl_master_rescan(
       
   586         ec_master_t *master, /**< EtherCAT master. */
       
   587         void *arg /**< ioctl() argument. */
       
   588         )
       
   589 {
       
   590     master->fsm.rescan_required = 1;
       
   591     return 0;
       
   592 }
       
   593 
       
   594 /*****************************************************************************/
       
   595 
       
   596 /** Set slave state.
       
   597  */
       
   598 static int ec_ioctl_slave_state(
       
   599         ec_master_t *master, /**< EtherCAT master. */
       
   600         void *arg /**< ioctl() argument. */
       
   601         )
       
   602 {
       
   603     ec_ioctl_slave_state_t data;
       
   604     ec_slave_t *slave;
       
   605 
       
   606     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
   607         return -EFAULT;
       
   608     }
       
   609 
       
   610     if (down_interruptible(&master->master_sem))
       
   611         return -EINTR;
       
   612 
       
   613     if (!(slave = ec_master_find_slave(
       
   614                     master, 0, data.slave_position))) {
       
   615         up(&master->master_sem);
       
   616         EC_MASTER_ERR(master, "Slave %u does not exist!\n",
       
   617                 data.slave_position);
       
   618         return -EINVAL;
       
   619     }
       
   620 
       
   621     ec_slave_request_state(slave, data.al_state);
       
   622 
       
   623     up(&master->master_sem);
       
   624     return 0;
       
   625 }
       
   626 
       
   627 /*****************************************************************************/
       
   628 
       
   629 /** Get slave SDO information.
       
   630  */
       
   631 static int ec_ioctl_slave_sdo(
       
   632         ec_master_t *master, /**< EtherCAT master. */
       
   633         void *arg /**< ioctl() argument. */
       
   634         )
       
   635 {
       
   636     ec_ioctl_slave_sdo_t data;
       
   637     const ec_slave_t *slave;
       
   638     const ec_sdo_t *sdo;
       
   639 
       
   640     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
   641         return -EFAULT;
       
   642     }
       
   643 
       
   644     if (down_interruptible(&master->master_sem))
       
   645         return -EINTR;
       
   646 
       
   647     if (!(slave = ec_master_find_slave_const(
       
   648                     master, 0, data.slave_position))) {
       
   649         up(&master->master_sem);
       
   650         EC_MASTER_ERR(master, "Slave %u does not exist!\n",
       
   651                 data.slave_position);
       
   652         return -EINVAL;
       
   653     }
       
   654 
       
   655     if (!(sdo = ec_slave_get_sdo_by_pos_const(
       
   656                     slave, data.sdo_position))) {
       
   657         up(&master->master_sem);
       
   658         EC_SLAVE_ERR(slave, "SDO %u does not exist!\n", data.sdo_position);
       
   659         return -EINVAL;
       
   660     }
       
   661 
       
   662     data.sdo_index = sdo->index;
       
   663     data.max_subindex = sdo->max_subindex;
       
   664     ec_ioctl_strcpy(data.name, sdo->name);
       
   665 
       
   666     up(&master->master_sem);
       
   667 
       
   668     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
   669         return -EFAULT;
       
   670 
       
   671     return 0;
       
   672 }
       
   673 
       
   674 /*****************************************************************************/
       
   675 
       
   676 /** Get slave SDO entry information.
       
   677  */
       
   678 static int ec_ioctl_slave_sdo_entry(
       
   679         ec_master_t *master, /**< EtherCAT master. */
       
   680         void *arg /**< ioctl() argument. */
       
   681         )
       
   682 {
       
   683     ec_ioctl_slave_sdo_entry_t data;
       
   684     const ec_slave_t *slave;
       
   685     const ec_sdo_t *sdo;
       
   686     const ec_sdo_entry_t *entry;
       
   687 
       
   688     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
   689         return -EFAULT;
       
   690     }
       
   691 
       
   692     if (down_interruptible(&master->master_sem))
       
   693         return -EINTR;
       
   694 
       
   695     if (!(slave = ec_master_find_slave_const(
       
   696                     master, 0, data.slave_position))) {
       
   697         up(&master->master_sem);
       
   698         EC_MASTER_ERR(master, "Slave %u does not exist!\n",
       
   699                 data.slave_position);
       
   700         return -EINVAL;
       
   701     }
       
   702 
       
   703     if (data.sdo_spec <= 0) {
       
   704         if (!(sdo = ec_slave_get_sdo_by_pos_const(
       
   705                         slave, -data.sdo_spec))) {
       
   706             up(&master->master_sem);
       
   707             EC_SLAVE_ERR(slave, "SDO %u does not exist!\n", -data.sdo_spec);
       
   708             return -EINVAL;
       
   709         }
       
   710     } else {
       
   711         if (!(sdo = ec_slave_get_sdo_const(
       
   712                         slave, data.sdo_spec))) {
       
   713             up(&master->master_sem);
       
   714             EC_SLAVE_ERR(slave, "SDO 0x%04X does not exist!\n",
       
   715                     data.sdo_spec);
       
   716             return -EINVAL;
       
   717         }
       
   718     }
       
   719 
       
   720     if (!(entry = ec_sdo_get_entry_const(
       
   721                     sdo, data.sdo_entry_subindex))) {
       
   722         up(&master->master_sem);
       
   723         EC_SLAVE_ERR(slave, "SDO entry 0x%04X:%02X does not exist!\n",
       
   724                 sdo->index, data.sdo_entry_subindex);
       
   725         return -EINVAL;
       
   726     }
       
   727 
       
   728     data.data_type = entry->data_type;
       
   729     data.bit_length = entry->bit_length;
       
   730     data.read_access[EC_SDO_ENTRY_ACCESS_PREOP] =
       
   731         entry->read_access[EC_SDO_ENTRY_ACCESS_PREOP];
       
   732     data.read_access[EC_SDO_ENTRY_ACCESS_SAFEOP] =
       
   733         entry->read_access[EC_SDO_ENTRY_ACCESS_SAFEOP];
       
   734     data.read_access[EC_SDO_ENTRY_ACCESS_OP] =
       
   735         entry->read_access[EC_SDO_ENTRY_ACCESS_OP];
       
   736     data.write_access[EC_SDO_ENTRY_ACCESS_PREOP] =
       
   737         entry->write_access[EC_SDO_ENTRY_ACCESS_PREOP];
       
   738     data.write_access[EC_SDO_ENTRY_ACCESS_SAFEOP] =
       
   739         entry->write_access[EC_SDO_ENTRY_ACCESS_SAFEOP];
       
   740     data.write_access[EC_SDO_ENTRY_ACCESS_OP] =
       
   741         entry->write_access[EC_SDO_ENTRY_ACCESS_OP];
       
   742     ec_ioctl_strcpy(data.description, entry->description);
       
   743 
       
   744     up(&master->master_sem);
       
   745 
       
   746     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
   747         return -EFAULT;
       
   748 
       
   749     return 0;
       
   750 }
       
   751 
       
   752 /*****************************************************************************/
       
   753 
       
   754 /** Upload SDO.
       
   755  */
       
   756 static int ec_ioctl_slave_sdo_upload(
       
   757         ec_master_t *master, /**< EtherCAT master. */
       
   758         void *arg /**< ioctl() argument. */
       
   759         )
       
   760 {
       
   761     ec_ioctl_slave_sdo_upload_t data;
       
   762     uint8_t *target;
       
   763     int ret;
       
   764 
       
   765     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
   766         return -EFAULT;
       
   767     }
       
   768 
       
   769     if (!(target = kmalloc(data.target_size, GFP_KERNEL))) {
       
   770         EC_MASTER_ERR(master, "Failed to allocate %u bytes"
       
   771                 " for SDO upload.\n", data.target_size);
       
   772         return -ENOMEM;
       
   773     }
       
   774 
       
   775     ret = ecrt_master_sdo_upload(master, data.slave_position,
       
   776             data.sdo_index, data.sdo_entry_subindex, target,
       
   777             data.target_size, &data.data_size, &data.abort_code);
       
   778 
       
   779     if (!ret) {
       
   780         if (copy_to_user((void __user *) data.target,
       
   781                     target, data.data_size)) {
       
   782             kfree(target);
       
   783             return -EFAULT;
       
   784         }
       
   785     }
       
   786 
       
   787     kfree(target);
       
   788 
       
   789     if (__copy_to_user((void __user *) arg, &data, sizeof(data))) {
       
   790         return -EFAULT;
       
   791     }
       
   792 
       
   793     return 0;
       
   794 }
       
   795 
       
   796 /*****************************************************************************/
       
   797 
       
   798 /** Download SDO.
       
   799  */
       
   800 static int ec_ioctl_slave_sdo_download(
       
   801         ec_master_t *master, /**< EtherCAT master. */
       
   802         void *arg /**< ioctl() argument. */
       
   803         )
       
   804 {
       
   805     ec_ioctl_slave_sdo_download_t data;
       
   806     uint8_t *sdo_data;
       
   807     int retval;
       
   808 
       
   809     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
   810         return -EFAULT;
       
   811     }
       
   812 
       
   813     if (!(sdo_data = kmalloc(data.data_size, GFP_KERNEL))) {
       
   814         EC_MASTER_ERR(master, "Failed to allocate %u bytes"
       
   815                 " for SDO download.\n", data.data_size);
       
   816         return -ENOMEM;
       
   817     }
       
   818 
       
   819     if (copy_from_user(sdo_data, (void __user *) data.data, data.data_size)) {
       
   820         kfree(sdo_data);
       
   821         return -EFAULT;
       
   822     }
       
   823 
       
   824     if (data.complete_access) {
       
   825         retval = ecrt_master_sdo_download_complete(master, data.slave_position,
       
   826                 data.sdo_index, sdo_data, data.data_size, &data.abort_code);
       
   827     } else {
       
   828         retval = ecrt_master_sdo_download(master, data.slave_position,
       
   829                 data.sdo_index, data.sdo_entry_subindex, sdo_data,
       
   830                 data.data_size, &data.abort_code);
       
   831     }
       
   832 
       
   833     kfree(sdo_data);
       
   834 
       
   835     if (__copy_to_user((void __user *) arg, &data, sizeof(data))) {
       
   836         retval = -EFAULT;
       
   837     }
       
   838 
       
   839     return retval;
       
   840 }
       
   841 
       
   842 /*****************************************************************************/
       
   843 
       
   844 /** Read a slave's SII.
       
   845  */
       
   846 static int ec_ioctl_slave_sii_read(
       
   847         ec_master_t *master, /**< EtherCAT master. */
       
   848         void *arg /**< ioctl() argument. */
       
   849         )
       
   850 {
       
   851     ec_ioctl_slave_sii_t data;
       
   852     const ec_slave_t *slave;
       
   853     int retval;
       
   854 
       
   855     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
   856         return -EFAULT;
       
   857     }
       
   858 
       
   859     if (down_interruptible(&master->master_sem))
       
   860         return -EINTR;
       
   861 
       
   862     if (!(slave = ec_master_find_slave_const(
       
   863                     master, 0, data.slave_position))) {
       
   864         up(&master->master_sem);
       
   865         EC_MASTER_ERR(master, "Slave %u does not exist!\n",
       
   866                 data.slave_position);
       
   867         return -EINVAL;
       
   868     }
       
   869 
       
   870     if (!data.nwords
       
   871             || data.offset + data.nwords > slave->sii_nwords) {
       
   872         up(&master->master_sem);
       
   873         EC_SLAVE_ERR(slave, "Invalid SII read offset/size %u/%u for slave SII"
       
   874                 " size %zu!\n", data.offset, data.nwords, slave->sii_nwords);
       
   875         return -EINVAL;
       
   876     }
       
   877 
       
   878     if (copy_to_user((void __user *) data.words,
       
   879                 slave->sii_words + data.offset, data.nwords * 2))
       
   880         retval = -EFAULT;
       
   881     else
       
   882         retval = 0;
       
   883 
       
   884     up(&master->master_sem);
       
   885     return retval;
       
   886 }
       
   887 
       
   888 /*****************************************************************************/
       
   889 
       
   890 /** Write a slave's SII.
       
   891  */
       
   892 static int ec_ioctl_slave_sii_write(
       
   893         ec_master_t *master, /**< EtherCAT master. */
       
   894         void *arg /**< ioctl() argument. */
       
   895         )
       
   896 {
       
   897     ec_ioctl_slave_sii_t data;
       
   898     ec_slave_t *slave;
       
   899     unsigned int byte_size;
       
   900     uint16_t *words;
       
   901     ec_sii_write_request_t request;
       
   902 
       
   903     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
   904         return -EFAULT;
       
   905     }
       
   906 
       
   907     if (!data.nwords)
       
   908         return 0;
       
   909 
       
   910     byte_size = sizeof(uint16_t) * data.nwords;
       
   911     if (!(words = kmalloc(byte_size, GFP_KERNEL))) {
       
   912         EC_MASTER_ERR(master, "Failed to allocate %u bytes"
       
   913                 " for SII contents.\n", byte_size);
       
   914         return -ENOMEM;
       
   915     }
       
   916 
       
   917     if (copy_from_user(words,
       
   918                 (void __user *) data.words, byte_size)) {
       
   919         kfree(words);
       
   920         return -EFAULT;
       
   921     }
       
   922 
       
   923     if (down_interruptible(&master->master_sem))
       
   924         return -EINTR;
       
   925 
       
   926     if (!(slave = ec_master_find_slave(
       
   927                     master, 0, data.slave_position))) {
       
   928         up(&master->master_sem);
       
   929         EC_MASTER_ERR(master, "Slave %u does not exist!\n",
       
   930                 data.slave_position);
       
   931         kfree(words);
       
   932         return -EINVAL;
       
   933     }
       
   934 
       
   935     // init SII write request
       
   936     INIT_LIST_HEAD(&request.list);
       
   937     request.slave = slave;
       
   938     request.words = words;
       
   939     request.offset = data.offset;
       
   940     request.nwords = data.nwords;
       
   941     request.state = EC_INT_REQUEST_QUEUED;
       
   942 
       
   943     // schedule SII write request.
       
   944     list_add_tail(&request.list, &master->sii_requests);
       
   945 
       
   946     up(&master->master_sem);
       
   947 
       
   948     // wait for processing through FSM
       
   949     if (wait_event_interruptible(master->sii_queue,
       
   950                 request.state != EC_INT_REQUEST_QUEUED)) {
       
   951         // interrupted by signal
       
   952         down(&master->master_sem);
       
   953         if (request.state == EC_INT_REQUEST_QUEUED) {
       
   954             // abort request
       
   955             list_del(&request.list);
       
   956             up(&master->master_sem);
       
   957             kfree(words);
       
   958             return -EINTR;
       
   959         }
       
   960         up(&master->master_sem);
       
   961     }
       
   962 
       
   963     // wait until master FSM has finished processing
       
   964     wait_event(master->sii_queue, request.state != EC_INT_REQUEST_BUSY);
       
   965 
       
   966     kfree(words);
       
   967 
       
   968     return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
       
   969 }
       
   970 
       
   971 /*****************************************************************************/
       
   972 
       
   973 /** Read a slave's registers.
       
   974  */
       
   975 static int ec_ioctl_slave_reg_read(
       
   976         ec_master_t *master, /**< EtherCAT master. */
       
   977         void *arg /**< ioctl() argument. */
       
   978         )
       
   979 {
       
   980     ec_ioctl_slave_reg_t data;
       
   981     ec_slave_t *slave;
       
   982     uint8_t *contents;
       
   983     ec_reg_request_t request;
       
   984 
       
   985     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
   986         return -EFAULT;
       
   987     }
       
   988 
       
   989     if (!data.length)
       
   990         return 0;
       
   991 
       
   992     if (!(contents = kmalloc(data.length, GFP_KERNEL))) {
       
   993         EC_MASTER_ERR(master, "Failed to allocate %u bytes"
       
   994                 " for register data.\n", data.length);
       
   995         return -ENOMEM;
       
   996     }
       
   997 
       
   998     if (down_interruptible(&master->master_sem))
       
   999         return -EINTR;
       
  1000 
       
  1001     if (!(slave = ec_master_find_slave(
       
  1002                     master, 0, data.slave_position))) {
       
  1003         up(&master->master_sem);
       
  1004         EC_MASTER_ERR(master, "Slave %u does not exist!\n",
       
  1005                 data.slave_position);
       
  1006         return -EINVAL;
       
  1007     }
       
  1008 
       
  1009     // init register request
       
  1010     INIT_LIST_HEAD(&request.list);
       
  1011     request.slave = slave;
       
  1012     request.dir = EC_DIR_INPUT;
       
  1013     request.data = contents;
       
  1014     request.offset = data.offset;
       
  1015     request.length = data.length;
       
  1016     request.state = EC_INT_REQUEST_QUEUED;
       
  1017 
       
  1018     // schedule request.
       
  1019     list_add_tail(&request.list, &master->reg_requests);
       
  1020 
       
  1021     up(&master->master_sem);
       
  1022 
       
  1023     // wait for processing through FSM
       
  1024     if (wait_event_interruptible(master->reg_queue,
       
  1025                 request.state != EC_INT_REQUEST_QUEUED)) {
       
  1026         // interrupted by signal
       
  1027         down(&master->master_sem);
       
  1028         if (request.state == EC_INT_REQUEST_QUEUED) {
       
  1029             // abort request
       
  1030             list_del(&request.list);
       
  1031             up(&master->master_sem);
       
  1032             kfree(contents);
       
  1033             return -EINTR;
       
  1034         }
       
  1035         up(&master->master_sem);
       
  1036     }
       
  1037 
       
  1038     // wait until master FSM has finished processing
       
  1039     wait_event(master->reg_queue, request.state != EC_INT_REQUEST_BUSY);
       
  1040 
       
  1041     if (request.state == EC_INT_REQUEST_SUCCESS) {
       
  1042         if (copy_to_user((void __user *) data.data, contents, data.length))
       
  1043             return -EFAULT;
       
  1044     }
       
  1045     kfree(contents);
       
  1046 
       
  1047     return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
       
  1048 }
       
  1049 
       
  1050 /*****************************************************************************/
       
  1051 
       
  1052 /** Write a slave's registers.
       
  1053  */
       
  1054 static int ec_ioctl_slave_reg_write(
       
  1055         ec_master_t *master, /**< EtherCAT master. */
       
  1056         void *arg /**< ioctl() argument. */
       
  1057         )
       
  1058 {
       
  1059     ec_ioctl_slave_reg_t data;
       
  1060     ec_slave_t *slave;
       
  1061     uint8_t *contents;
       
  1062     ec_reg_request_t request;
       
  1063 
       
  1064     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
  1065         return -EFAULT;
       
  1066     }
       
  1067 
       
  1068     if (!data.length)
       
  1069         return 0;
       
  1070 
       
  1071     if (!(contents = kmalloc(data.length, GFP_KERNEL))) {
       
  1072         EC_MASTER_ERR(master, "Failed to allocate %u bytes"
       
  1073                 " for register data.\n", data.length);
       
  1074         return -ENOMEM;
       
  1075     }
       
  1076 
       
  1077     if (copy_from_user(contents, (void __user *) data.data, data.length)) {
       
  1078         kfree(contents);
       
  1079         return -EFAULT;
       
  1080     }
       
  1081 
       
  1082     if (down_interruptible(&master->master_sem))
       
  1083         return -EINTR;
       
  1084 
       
  1085     if (!(slave = ec_master_find_slave(
       
  1086                     master, 0, data.slave_position))) {
       
  1087         up(&master->master_sem);
       
  1088         EC_MASTER_ERR(master, "Slave %u does not exist!\n",
       
  1089                 data.slave_position);
       
  1090         kfree(contents);
       
  1091         return -EINVAL;
       
  1092     }
       
  1093 
       
  1094     // init register request
       
  1095     INIT_LIST_HEAD(&request.list);
       
  1096     request.slave = slave;
       
  1097     request.dir = EC_DIR_OUTPUT;
       
  1098     request.data = contents;
       
  1099     request.offset = data.offset;
       
  1100     request.length = data.length;
       
  1101     request.state = EC_INT_REQUEST_QUEUED;
       
  1102 
       
  1103     // schedule request.
       
  1104     list_add_tail(&request.list, &master->reg_requests);
       
  1105 
       
  1106     up(&master->master_sem);
       
  1107 
       
  1108     // wait for processing through FSM
       
  1109     if (wait_event_interruptible(master->reg_queue,
       
  1110                 request.state != EC_INT_REQUEST_QUEUED)) {
       
  1111         // interrupted by signal
       
  1112         down(&master->master_sem);
       
  1113         if (request.state == EC_INT_REQUEST_QUEUED) {
       
  1114             // abort request
       
  1115             list_del(&request.list);
       
  1116             up(&master->master_sem);
       
  1117             kfree(contents);
       
  1118             return -EINTR;
       
  1119         }
       
  1120         up(&master->master_sem);
       
  1121     }
       
  1122 
       
  1123     // wait until master FSM has finished processing
       
  1124     wait_event(master->reg_queue, request.state != EC_INT_REQUEST_BUSY);
       
  1125 
       
  1126     kfree(contents);
       
  1127 
       
  1128     return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
       
  1129 }
       
  1130 
       
  1131 /*****************************************************************************/
       
  1132 
       
  1133 /** Get slave configuration information.
       
  1134  */
       
  1135 static int ec_ioctl_config(
       
  1136         ec_master_t *master, /**< EtherCAT master. */
       
  1137         void *arg /**< ioctl() argument. */
       
  1138         )
       
  1139 {
       
  1140     ec_ioctl_config_t data;
       
  1141     const ec_slave_config_t *sc;
       
  1142     uint8_t i;
       
  1143 
       
  1144     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
  1145         return -EFAULT;
       
  1146     }
       
  1147 
       
  1148     if (down_interruptible(&master->master_sem))
       
  1149         return -EINTR;
       
  1150 
       
  1151     if (!(sc = ec_master_get_config_const(
       
  1152                     master, data.config_index))) {
       
  1153         up(&master->master_sem);
       
  1154         EC_MASTER_ERR(master, "Slave config %u does not exist!\n",
       
  1155                 data.config_index);
       
  1156         return -EINVAL;
       
  1157     }
       
  1158 
       
  1159     data.alias = sc->alias;
       
  1160     data.position = sc->position;
       
  1161     data.vendor_id = sc->vendor_id;
       
  1162     data.product_code = sc->product_code;
       
  1163     for (i = 0; i < EC_MAX_SYNC_MANAGERS; i++) {
       
  1164         data.syncs[i].dir = sc->sync_configs[i].dir;
       
  1165         data.syncs[i].watchdog_mode = sc->sync_configs[i].watchdog_mode;
       
  1166         data.syncs[i].pdo_count =
       
  1167             ec_pdo_list_count(&sc->sync_configs[i].pdos);
       
  1168     }
       
  1169     data.watchdog_divider = sc->watchdog_divider;
       
  1170     data.watchdog_intervals = sc->watchdog_intervals;
       
  1171     data.sdo_count = ec_slave_config_sdo_count(sc);
       
  1172     data.idn_count = ec_slave_config_idn_count(sc);
       
  1173     data.slave_position = sc->slave ? sc->slave->ring_position : -1;
       
  1174     data.dc_assign_activate = sc->dc_assign_activate;
       
  1175     for (i = 0; i < EC_SYNC_SIGNAL_COUNT; i++) {
       
  1176         data.dc_sync[i] = sc->dc_sync[i];
       
  1177     }
       
  1178 
       
  1179     up(&master->master_sem);
       
  1180 
       
  1181     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
  1182         return -EFAULT;
       
  1183 
       
  1184     return 0;
       
  1185 }
       
  1186 
       
  1187 /*****************************************************************************/
       
  1188 
       
  1189 /** Get slave configuration PDO information.
       
  1190  */
       
  1191 static int ec_ioctl_config_pdo(
       
  1192         ec_master_t *master, /**< EtherCAT master. */
       
  1193         void *arg /**< ioctl() argument. */
       
  1194         )
       
  1195 {
       
  1196     ec_ioctl_config_pdo_t data;
       
  1197     const ec_slave_config_t *sc;
       
  1198     const ec_pdo_t *pdo;
       
  1199 
       
  1200     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
  1201         return -EFAULT;
       
  1202     }
       
  1203 
       
  1204     if (data.sync_index >= EC_MAX_SYNC_MANAGERS) {
       
  1205         EC_MASTER_ERR(master, "Invalid sync manager index %u!\n",
       
  1206                 data.sync_index);
       
  1207         return -EINVAL;
       
  1208     }
       
  1209 
       
  1210     if (down_interruptible(&master->master_sem))
       
  1211         return -EINTR;
       
  1212 
       
  1213     if (!(sc = ec_master_get_config_const(
       
  1214                     master, data.config_index))) {
       
  1215         up(&master->master_sem);
       
  1216         EC_MASTER_ERR(master, "Slave config %u does not exist!\n",
       
  1217                 data.config_index);
       
  1218         return -EINVAL;
       
  1219     }
       
  1220 
       
  1221     if (!(pdo = ec_pdo_list_find_pdo_by_pos_const(
       
  1222                     &sc->sync_configs[data.sync_index].pdos,
       
  1223                     data.pdo_pos))) {
       
  1224         up(&master->master_sem);
       
  1225         EC_MASTER_ERR(master, "Invalid PDO position!\n");
       
  1226         return -EINVAL;
       
  1227     }
       
  1228 
       
  1229     data.index = pdo->index;
       
  1230     data.entry_count = ec_pdo_entry_count(pdo);
       
  1231     ec_ioctl_strcpy(data.name, pdo->name);
       
  1232 
       
  1233     up(&master->master_sem);
       
  1234 
       
  1235     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
  1236         return -EFAULT;
       
  1237 
       
  1238     return 0;
       
  1239 }
       
  1240 
       
  1241 /*****************************************************************************/
       
  1242 
       
  1243 /** Get slave configuration PDO entry information.
       
  1244  */
       
  1245 static int ec_ioctl_config_pdo_entry(
       
  1246         ec_master_t *master, /**< EtherCAT master. */
       
  1247         void *arg /**< ioctl() argument. */
       
  1248         )
       
  1249 {
       
  1250     ec_ioctl_config_pdo_entry_t data;
       
  1251     const ec_slave_config_t *sc;
       
  1252     const ec_pdo_t *pdo;
       
  1253     const ec_pdo_entry_t *entry;
       
  1254 
       
  1255     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
  1256         return -EFAULT;
       
  1257     }
       
  1258 
       
  1259     if (data.sync_index >= EC_MAX_SYNC_MANAGERS) {
       
  1260         EC_MASTER_ERR(master, "Invalid sync manager index %u!\n",
       
  1261                 data.sync_index);
       
  1262         return -EINVAL;
       
  1263     }
       
  1264 
       
  1265     if (down_interruptible(&master->master_sem))
       
  1266         return -EINTR;
       
  1267 
       
  1268     if (!(sc = ec_master_get_config_const(
       
  1269                     master, data.config_index))) {
       
  1270         up(&master->master_sem);
       
  1271         EC_MASTER_ERR(master, "Slave config %u does not exist!\n",
       
  1272                 data.config_index);
       
  1273         return -EINVAL;
       
  1274     }
       
  1275 
       
  1276     if (!(pdo = ec_pdo_list_find_pdo_by_pos_const(
       
  1277                     &sc->sync_configs[data.sync_index].pdos,
       
  1278                     data.pdo_pos))) {
       
  1279         up(&master->master_sem);
       
  1280         EC_MASTER_ERR(master, "Invalid PDO position!\n");
       
  1281         return -EINVAL;
       
  1282     }
       
  1283 
       
  1284     if (!(entry = ec_pdo_find_entry_by_pos_const(
       
  1285                     pdo, data.entry_pos))) {
       
  1286         up(&master->master_sem);
       
  1287         EC_MASTER_ERR(master, "Entry not found!\n");
       
  1288         return -EINVAL;
       
  1289     }
       
  1290 
       
  1291     data.index = entry->index;
       
  1292     data.subindex = entry->subindex;
       
  1293     data.bit_length = entry->bit_length;
       
  1294     ec_ioctl_strcpy(data.name, entry->name);
       
  1295 
       
  1296     up(&master->master_sem);
       
  1297 
       
  1298     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
  1299         return -EFAULT;
       
  1300 
       
  1301     return 0;
       
  1302 }
       
  1303 
       
  1304 /*****************************************************************************/
       
  1305 
       
  1306 /** Get slave configuration SDO information.
       
  1307  */
       
  1308 static int ec_ioctl_config_sdo(
       
  1309         ec_master_t *master, /**< EtherCAT master. */
       
  1310         void *arg /**< ioctl() argument. */
       
  1311         )
       
  1312 {
       
  1313     ec_ioctl_config_sdo_t *ioctl;
       
  1314     const ec_slave_config_t *sc;
       
  1315     const ec_sdo_request_t *req;
       
  1316 
       
  1317     if (!(ioctl = kmalloc(sizeof(*ioctl), GFP_KERNEL))) {
       
  1318         return -ENOMEM;
       
  1319     }
       
  1320 
       
  1321     if (copy_from_user(ioctl, (void __user *) arg, sizeof(*ioctl))) {
       
  1322         kfree(ioctl);
       
  1323         return -EFAULT;
       
  1324     }
       
  1325 
       
  1326     if (down_interruptible(&master->master_sem)) {
       
  1327         kfree(ioctl);
       
  1328         return -EINTR;
       
  1329     }
       
  1330 
       
  1331     if (!(sc = ec_master_get_config_const(
       
  1332                     master, ioctl->config_index))) {
       
  1333         up(&master->master_sem);
       
  1334         EC_MASTER_ERR(master, "Slave config %u does not exist!\n",
       
  1335                 ioctl->config_index);
       
  1336         kfree(ioctl);
       
  1337         return -EINVAL;
       
  1338     }
       
  1339 
       
  1340     if (!(req = ec_slave_config_get_sdo_by_pos_const(
       
  1341                     sc, ioctl->sdo_pos))) {
       
  1342         up(&master->master_sem);
       
  1343         EC_MASTER_ERR(master, "Invalid SDO position!\n");
       
  1344         kfree(ioctl);
       
  1345         return -EINVAL;
       
  1346     }
       
  1347 
       
  1348     ioctl->index = req->index;
       
  1349     ioctl->subindex = req->subindex;
       
  1350     ioctl->size = req->data_size;
       
  1351     memcpy(ioctl->data, req->data,
       
  1352             min((u32) ioctl->size, (u32) EC_MAX_SDO_DATA_SIZE));
       
  1353 
       
  1354     up(&master->master_sem);
       
  1355 
       
  1356     if (copy_to_user((void __user *) arg, ioctl, sizeof(*ioctl))) {
       
  1357         kfree(ioctl);
       
  1358         return -EFAULT;
       
  1359     }
       
  1360 
       
  1361     kfree(ioctl);
       
  1362     return 0;
       
  1363 }
       
  1364 
       
  1365 /*****************************************************************************/
       
  1366 
       
  1367 /** Get slave configuration IDN information.
       
  1368  */
       
  1369 static int ec_ioctl_config_idn(
       
  1370         ec_master_t *master, /**< EtherCAT master. */
       
  1371         void *arg /**< ioctl() argument. */
       
  1372         )
       
  1373 {
       
  1374     ec_ioctl_config_idn_t *ioctl;
       
  1375     const ec_slave_config_t *sc;
       
  1376     const ec_soe_request_t *req;
       
  1377 
       
  1378     if (!(ioctl = kmalloc(sizeof(*ioctl), GFP_KERNEL))) {
       
  1379         return -ENOMEM;
       
  1380     }
       
  1381 
       
  1382     if (copy_from_user(ioctl, (void __user *) arg, sizeof(*ioctl))) {
       
  1383         kfree(ioctl);
       
  1384         return -EFAULT;
       
  1385     }
       
  1386 
       
  1387     if (down_interruptible(&master->master_sem)) {
       
  1388         kfree(ioctl);
       
  1389         return -EINTR;
       
  1390     }
       
  1391 
       
  1392     if (!(sc = ec_master_get_config_const(
       
  1393                     master, ioctl->config_index))) {
       
  1394         up(&master->master_sem);
       
  1395         EC_MASTER_ERR(master, "Slave config %u does not exist!\n",
       
  1396                 ioctl->config_index);
       
  1397         kfree(ioctl);
       
  1398         return -EINVAL;
       
  1399     }
       
  1400 
       
  1401     if (!(req = ec_slave_config_get_idn_by_pos_const(
       
  1402                     sc, ioctl->idn_pos))) {
       
  1403         up(&master->master_sem);
       
  1404         EC_MASTER_ERR(master, "Invalid IDN position!\n");
       
  1405         kfree(ioctl);
       
  1406         return -EINVAL;
       
  1407     }
       
  1408 
       
  1409     ioctl->drive_no = req->drive_no;
       
  1410     ioctl->idn = req->idn;
       
  1411     ioctl->state = req->state;
       
  1412     ioctl->size = req->data_size;
       
  1413     memcpy(ioctl->data, req->data,
       
  1414             min((u32) ioctl->size, (u32) EC_MAX_IDN_DATA_SIZE));
       
  1415 
       
  1416     up(&master->master_sem);
       
  1417 
       
  1418     if (copy_to_user((void __user *) arg, ioctl, sizeof(*ioctl))) {
       
  1419         kfree(ioctl);
       
  1420         return -EFAULT;
       
  1421     }
       
  1422 
       
  1423     kfree(ioctl);
       
  1424     return 0;
       
  1425 }
       
  1426 
       
  1427 /*****************************************************************************/
       
  1428 
       
  1429 #ifdef EC_EOE
       
  1430 
       
  1431 /** Get EoE handler information.
       
  1432  */
       
  1433 static int ec_ioctl_eoe_handler(
       
  1434         ec_master_t *master, /**< EtherCAT master. */
       
  1435         void *arg /**< ioctl() argument. */
       
  1436         )
       
  1437 {
       
  1438     ec_ioctl_eoe_handler_t data;
       
  1439     const ec_eoe_t *eoe;
       
  1440 
       
  1441     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
  1442         return -EFAULT;
       
  1443     }
       
  1444 
       
  1445     if (down_interruptible(&master->master_sem))
       
  1446         return -EINTR;
       
  1447 
       
  1448     if (!(eoe = ec_master_get_eoe_handler_const(master, data.eoe_index))) {
       
  1449         up(&master->master_sem);
       
  1450         EC_MASTER_ERR(master, "EoE handler %u does not exist!\n",
       
  1451                 data.eoe_index);
       
  1452         return -EINVAL;
       
  1453     }
       
  1454 
       
  1455     if (eoe->slave) {
       
  1456         data.slave_position = eoe->slave->ring_position;
       
  1457     } else {
       
  1458         data.slave_position = 0xffff;
       
  1459     }
       
  1460     snprintf(data.name, EC_DATAGRAM_NAME_SIZE, eoe->dev->name);
       
  1461     data.open = eoe->opened;
       
  1462     data.rx_bytes = eoe->stats.tx_bytes;
       
  1463     data.rx_rate = eoe->tx_rate;
       
  1464     data.tx_bytes = eoe->stats.rx_bytes;
       
  1465     data.tx_rate = eoe->tx_rate;
       
  1466     data.tx_queued_frames = eoe->tx_queued_frames;
       
  1467     data.tx_queue_size = eoe->tx_queue_size;
       
  1468 
       
  1469     up(&master->master_sem);
       
  1470 
       
  1471     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
  1472         return -EFAULT;
       
  1473 
       
  1474     return 0;
       
  1475 }
       
  1476 
       
  1477 #endif
       
  1478 
       
  1479 /*****************************************************************************/
       
  1480 
       
  1481 /** Request the master from userspace.
       
  1482  */
       
  1483 static int ec_ioctl_request(
       
  1484         ec_master_t *master, /**< EtherCAT master. */
       
  1485         void *arg, /**< ioctl() argument. */
       
  1486         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1487         )
       
  1488 {
       
  1489     ec_master_t *m;
       
  1490     int ret = 0;
       
  1491 
       
  1492     m = ecrt_request_master_err(master->index);
       
  1493     if (IS_ERR(m)) {
       
  1494         ret = PTR_ERR(m);
       
  1495     } else {
       
  1496         ctx->requested = 1;
       
  1497     }
       
  1498 
       
  1499     return ret;
       
  1500 }
       
  1501 
       
  1502 /*****************************************************************************/
       
  1503 
       
  1504 /** Create a domain.
       
  1505  */
       
  1506 static int ec_ioctl_create_domain(
       
  1507         ec_master_t *master, /**< EtherCAT master. */
       
  1508         void *arg, /**< ioctl() argument. */
       
  1509         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1510         )
       
  1511 {
       
  1512     ec_domain_t *domain;
       
  1513 
       
  1514     if (unlikely(!ctx->requested))
       
  1515         return -EPERM;
       
  1516 
       
  1517     domain = ecrt_master_create_domain_err(master);
       
  1518     if (IS_ERR(domain))
       
  1519         return PTR_ERR(domain);
       
  1520 
       
  1521     return domain->index;
       
  1522 }
       
  1523 
       
  1524 /*****************************************************************************/
       
  1525 
       
  1526 /** Create a slave configuration.
       
  1527  */
       
  1528 static int ec_ioctl_create_slave_config(
       
  1529         ec_master_t *master, /**< EtherCAT master. */
       
  1530         void *arg, /**< ioctl() argument. */
       
  1531         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1532         )
       
  1533 {
       
  1534     ec_ioctl_config_t data;
       
  1535     ec_slave_config_t *sc, *entry;
       
  1536 
       
  1537     if (unlikely(!ctx->requested))
       
  1538         return -EPERM;
       
  1539 
       
  1540     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
  1541         return -EFAULT;
       
  1542     }
       
  1543 
       
  1544     sc = ecrt_master_slave_config_err(master, data.alias, data.position,
       
  1545             data.vendor_id, data.product_code);
       
  1546     if (IS_ERR(sc))
       
  1547         return PTR_ERR(sc);
       
  1548 
       
  1549     data.config_index = 0;
       
  1550 
       
  1551     if (down_interruptible(&master->master_sem))
       
  1552         return -EINTR;
       
  1553 
       
  1554     list_for_each_entry(entry, &master->configs, list) {
       
  1555         if (entry == sc)
       
  1556             break;
       
  1557         data.config_index++;
       
  1558     }
       
  1559 
       
  1560     up(&master->master_sem);
       
  1561 
       
  1562     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
  1563         return -EFAULT;
       
  1564 
       
  1565     return 0;
       
  1566 }
       
  1567 
       
  1568 /*****************************************************************************/
       
  1569 
       
  1570 /** Activates the master.
       
  1571  */
       
  1572 static int ec_ioctl_activate(
       
  1573         ec_master_t *master, /**< EtherCAT master. */
       
  1574         void *arg, /**< ioctl() argument. */
       
  1575         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1576         )
       
  1577 {
       
  1578     ec_ioctl_master_activate_t io;
       
  1579     ec_domain_t *domain;
       
  1580     off_t offset;
       
  1581     int ret;
       
  1582 
       
  1583     if (unlikely(!ctx->requested))
       
  1584         return -EPERM;
       
  1585 
       
  1586     io.process_data = NULL;
       
  1587 
       
  1588     /* Get the sum of the domains' process data sizes. */
       
  1589 
       
  1590     ctx->process_data_size = 0;
       
  1591 
       
  1592     if (down_interruptible(&master->master_sem))
       
  1593         return -EINTR;
       
  1594 
       
  1595     list_for_each_entry(domain, &master->domains, list) {
       
  1596         ctx->process_data_size += ecrt_domain_size(domain);
       
  1597     }
       
  1598 
       
  1599     up(&master->master_sem);
       
  1600 
       
  1601     if (ctx->process_data_size) {
       
  1602         ctx->process_data = vmalloc(ctx->process_data_size);
       
  1603         if (!ctx->process_data) {
       
  1604             ctx->process_data_size = 0;
       
  1605             return -ENOMEM;
       
  1606         }
       
  1607 
       
  1608         /* Set the memory as external process data memory for the
       
  1609          * domains.
       
  1610 		 */
       
  1611         offset = 0;
       
  1612         list_for_each_entry(domain, &master->domains, list) {
       
  1613             ecrt_domain_external_memory(domain,
       
  1614                     ctx->process_data + offset);
       
  1615             offset += ecrt_domain_size(domain);
       
  1616         }
       
  1617 
       
  1618 #ifdef EC_IOCTL_RTDM
       
  1619 		/* RTDM uses a different approach for memory-mapping, which has to be
       
  1620 		 * initiated by the kernel.
       
  1621 		 */
       
  1622 		ret = ec_rtdm_mmap(ctx, &io.process_data);
       
  1623         if (ret < 0) {
       
  1624             EC_MASTER_ERR(master, "Failed to map process data"
       
  1625                     " memory to user space (code %i).\n", ret);
       
  1626             return ret;
       
  1627         }
       
  1628 #endif
       
  1629     }
       
  1630 
       
  1631     io.process_data_size = ctx->process_data_size;
       
  1632 
       
  1633 #ifndef EC_IOCTL_RTDM
       
  1634     ecrt_master_callbacks(master, ec_master_internal_send_cb,
       
  1635             ec_master_internal_receive_cb, master);
       
  1636 #endif
       
  1637 
       
  1638     ret = ecrt_master_activate(master);
       
  1639     if (ret < 0)
       
  1640         return ret;
       
  1641 
       
  1642     if (copy_to_user((void __user *) arg, &io,
       
  1643                 sizeof(ec_ioctl_master_activate_t)))
       
  1644         return -EFAULT;
       
  1645 
       
  1646     return 0;
       
  1647 }
       
  1648 
       
  1649 /*****************************************************************************/
       
  1650 
       
  1651 /** Deactivates the master.
       
  1652  */
       
  1653 static int ec_ioctl_deactivate(
       
  1654         ec_master_t *master, /**< EtherCAT master. */
       
  1655         void *arg, /**< ioctl() argument. */
       
  1656         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1657         )
       
  1658 {
       
  1659     if (unlikely(!ctx->requested))
       
  1660         return -EPERM;
       
  1661 
       
  1662     ecrt_master_deactivate(master);
       
  1663     return 0;
       
  1664 }
       
  1665 
       
  1666 /*****************************************************************************/
       
  1667 
       
  1668 /** Set max. number of databytes in a cycle
       
  1669  */
       
  1670 static int ec_ioctl_set_send_interval(
       
  1671         ec_master_t *master, /**< EtherCAT master. */
       
  1672         void *arg, /**< ioctl() argument. */
       
  1673         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1674         )
       
  1675 {
       
  1676     size_t send_interval;
       
  1677 
       
  1678     if (copy_from_user(&send_interval, (void __user *) arg,
       
  1679                 sizeof(send_interval))) {
       
  1680         return -EFAULT;
       
  1681     }
       
  1682 
       
  1683     if (down_interruptible(&master->master_sem))
       
  1684         return -EINTR;
       
  1685 
       
  1686     ec_master_set_send_interval(master, send_interval);
       
  1687 
       
  1688     up(&master->master_sem);
       
  1689     return 0;
       
  1690 }
       
  1691 
       
  1692 /*****************************************************************************/
       
  1693 
       
  1694 /** Send frames.
       
  1695  */
       
  1696 static int ec_ioctl_send(
       
  1697         ec_master_t *master, /**< EtherCAT master. */
       
  1698         void *arg, /**< ioctl() argument. */
       
  1699         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1700         )
       
  1701 {
       
  1702     if (unlikely(!ctx->requested))
       
  1703         return -EPERM;
       
  1704 
       
  1705     down(&master->io_sem);
       
  1706     ecrt_master_send(master);
       
  1707     up(&master->io_sem);
       
  1708     return 0;
       
  1709 }
       
  1710 
       
  1711 /*****************************************************************************/
       
  1712 
       
  1713 /** Receive frames.
       
  1714  */
       
  1715 static int ec_ioctl_receive(
       
  1716         ec_master_t *master, /**< EtherCAT master. */
       
  1717         void *arg, /**< ioctl() argument. */
       
  1718         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1719         )
       
  1720 {
       
  1721     if (unlikely(!ctx->requested))
       
  1722         return -EPERM;
       
  1723 
       
  1724     down(&master->io_sem);
       
  1725     ecrt_master_receive(master);
       
  1726     up(&master->io_sem);
       
  1727     return 0;
       
  1728 }
       
  1729 
       
  1730 /*****************************************************************************/
       
  1731 
       
  1732 /** Get the master state.
       
  1733  */
       
  1734 static int ec_ioctl_master_state(
       
  1735         ec_master_t *master, /**< EtherCAT master. */
       
  1736         void *arg, /**< ioctl() argument. */
       
  1737         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1738         )
       
  1739 {
       
  1740     ec_master_state_t data;
       
  1741 
       
  1742     if (unlikely(!ctx->requested))
       
  1743         return -EPERM;
       
  1744 
       
  1745     ecrt_master_state(master, &data);
       
  1746 
       
  1747     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
  1748         return -EFAULT;
       
  1749 
       
  1750     return 0;
       
  1751 }
       
  1752 
       
  1753 /*****************************************************************************/
       
  1754 
       
  1755 /** Get the master state.
       
  1756  */
       
  1757 static int ec_ioctl_master_link_state(
       
  1758         ec_master_t *master, /**< EtherCAT master. */
       
  1759         void *arg, /**< ioctl() argument. */
       
  1760         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1761         )
       
  1762 {
       
  1763     ec_ioctl_link_state_t ioctl;
       
  1764     ec_master_link_state_t state;
       
  1765     int ret;
       
  1766 
       
  1767     if (unlikely(!ctx->requested)) {
       
  1768         return -EPERM;
       
  1769     }
       
  1770 
       
  1771     if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl))) {
       
  1772         return -EFAULT;
       
  1773     }
       
  1774 
       
  1775     ret = ecrt_master_link_state(master, ioctl.dev_idx, &state);
       
  1776     if (ret < 0) {
       
  1777         return ret;
       
  1778     }
       
  1779 
       
  1780     if (copy_to_user((void __user *) ioctl.state, &state, sizeof(state))) {
       
  1781         return -EFAULT;
       
  1782     }
       
  1783 
       
  1784     return 0;
       
  1785 }
       
  1786 
       
  1787 /*****************************************************************************/
       
  1788 
       
  1789 /** Set the master dc app time.
       
  1790  */
       
  1791 static int ec_ioctl_app_time(
       
  1792         ec_master_t *master, /**< EtherCAT master. */
       
  1793         void *arg, /**< ioctl() argument. */
       
  1794         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1795         )
       
  1796 {
       
  1797     ec_ioctl_app_time_t data;
       
  1798 
       
  1799     if (unlikely(!ctx->requested))
       
  1800         return -EPERM;
       
  1801 
       
  1802     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
  1803         return -EFAULT;
       
  1804     }
       
  1805 
       
  1806     ecrt_master_application_time(master, data.app_time);
       
  1807     return 0;
       
  1808 }
       
  1809 
       
  1810 /*****************************************************************************/
       
  1811 
       
  1812 /** Sync the reference clock.
       
  1813  */
       
  1814 static int ec_ioctl_sync_ref(
       
  1815         ec_master_t *master, /**< EtherCAT master. */
       
  1816         void *arg, /**< ioctl() argument. */
       
  1817         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1818         )
       
  1819 {
       
  1820     if (unlikely(!ctx->requested))
       
  1821         return -EPERM;
       
  1822 
       
  1823     down(&master->io_sem);
       
  1824     ecrt_master_sync_reference_clock(master);
       
  1825     up(&master->io_sem);
       
  1826     return 0;
       
  1827 }
       
  1828 
       
  1829 /*****************************************************************************/
       
  1830 
       
  1831 /** Sync the slave clocks.
       
  1832  */
       
  1833 static int ec_ioctl_sync_slaves(
       
  1834         ec_master_t *master, /**< EtherCAT master. */
       
  1835         void *arg, /**< ioctl() argument. */
       
  1836         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1837         )
       
  1838 {
       
  1839     if (unlikely(!ctx->requested))
       
  1840         return -EPERM;
       
  1841 
       
  1842     down(&master->io_sem);
       
  1843     ecrt_master_sync_slave_clocks(master);
       
  1844     up(&master->io_sem);
       
  1845     return 0;
       
  1846 }
       
  1847 
       
  1848 /*****************************************************************************/
       
  1849 
       
  1850 /** Queue the sync monitoring datagram.
       
  1851  */
       
  1852 static int ec_ioctl_sync_mon_queue(
       
  1853         ec_master_t *master, /**< EtherCAT master. */
       
  1854         void *arg, /**< ioctl() argument. */
       
  1855         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1856         )
       
  1857 {
       
  1858     if (unlikely(!ctx->requested))
       
  1859         return -EPERM;
       
  1860 
       
  1861     down(&master->io_sem);
       
  1862     ecrt_master_sync_monitor_queue(master);
       
  1863     up(&master->io_sem);
       
  1864     return 0;
       
  1865 }
       
  1866 
       
  1867 /*****************************************************************************/
       
  1868 
       
  1869 /** Processes the sync monitoring datagram.
       
  1870  */
       
  1871 static int ec_ioctl_sync_mon_process(
       
  1872         ec_master_t *master, /**< EtherCAT master. */
       
  1873         void *arg, /**< ioctl() argument. */
       
  1874         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1875         )
       
  1876 {
       
  1877     uint32_t time_diff;
       
  1878 
       
  1879     if (unlikely(!ctx->requested))
       
  1880         return -EPERM;
       
  1881 
       
  1882     down(&master->io_sem);
       
  1883     time_diff = ecrt_master_sync_monitor_process(master);
       
  1884     up(&master->io_sem);
       
  1885 
       
  1886     if (copy_to_user((void __user *) arg, &time_diff, sizeof(time_diff)))
       
  1887         return -EFAULT;
       
  1888 
       
  1889     return 0;
       
  1890 }
       
  1891 
       
  1892 /*****************************************************************************/
       
  1893 
       
  1894 /** Reset configuration.
       
  1895  */
       
  1896 static int ec_ioctl_reset(
       
  1897         ec_master_t *master, /**< EtherCAT master. */
       
  1898         void *arg, /**< ioctl() argument. */
       
  1899         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1900         )
       
  1901 {
       
  1902     if (unlikely(!ctx->requested))
       
  1903         return -EPERM;
       
  1904 
       
  1905     down(&master->master_sem);
       
  1906     ecrt_master_reset(master);
       
  1907     up(&master->master_sem);
       
  1908     return 0;
       
  1909 }
       
  1910 
       
  1911 /*****************************************************************************/
       
  1912 
       
  1913 /** Configure a sync manager.
       
  1914  */
       
  1915 static int ec_ioctl_sc_sync(
       
  1916         ec_master_t *master, /**< EtherCAT master. */
       
  1917         void *arg, /**< ioctl() argument. */
       
  1918         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1919         )
       
  1920 {
       
  1921     ec_ioctl_config_t data;
       
  1922     ec_slave_config_t *sc;
       
  1923     unsigned int i;
       
  1924     int ret = 0;
       
  1925 
       
  1926     if (unlikely(!ctx->requested)) {
       
  1927         ret = -EPERM;
       
  1928         goto out_return;
       
  1929     }
       
  1930 
       
  1931     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
  1932         ret = -EFAULT;
       
  1933         goto out_return;
       
  1934     }
       
  1935 
       
  1936     if (down_interruptible(&master->master_sem)) {
       
  1937         ret = -EINTR;
       
  1938         goto out_return;
       
  1939     }
       
  1940 
       
  1941     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  1942         ret = -ENOENT;
       
  1943         goto out_up;
       
  1944     }
       
  1945 
       
  1946     for (i = 0; i < EC_MAX_SYNC_MANAGERS; i++) {
       
  1947         if (data.syncs[i].config_this) {
       
  1948             if (ecrt_slave_config_sync_manager(sc, i, data.syncs[i].dir,
       
  1949                         data.syncs[i].watchdog_mode)) {
       
  1950                 ret = -EINVAL;
       
  1951                 goto out_up;
       
  1952             }
       
  1953         }
       
  1954     }
       
  1955 
       
  1956 out_up:
       
  1957     up(&master->master_sem);
       
  1958 out_return:
       
  1959     return ret;
       
  1960 }
       
  1961 
       
  1962 /*****************************************************************************/
       
  1963 
       
  1964 /** Configure a slave's watchdogs.
       
  1965  */
       
  1966 static int ec_ioctl_sc_watchdog(
       
  1967         ec_master_t *master, /**< EtherCAT master. */
       
  1968         void *arg, /**< ioctl() argument. */
       
  1969         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  1970         )
       
  1971 {
       
  1972     ec_ioctl_config_t data;
       
  1973     ec_slave_config_t *sc;
       
  1974     int ret = 0;
       
  1975 
       
  1976     if (unlikely(!ctx->requested)) {
       
  1977         ret = -EPERM;
       
  1978         goto out_return;
       
  1979     }
       
  1980 
       
  1981     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
  1982         ret = -EFAULT;
       
  1983         goto out_return;
       
  1984     }
       
  1985 
       
  1986     if (down_interruptible(&master->master_sem)) {
       
  1987         ret = -EINTR;
       
  1988         goto out_return;
       
  1989     }
       
  1990 
       
  1991     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  1992         ret = -ENOENT;
       
  1993         goto out_up;
       
  1994     }
       
  1995 
       
  1996     ecrt_slave_config_watchdog(sc,
       
  1997             data.watchdog_divider, data.watchdog_intervals);
       
  1998 
       
  1999 out_up:
       
  2000     up(&master->master_sem);
       
  2001 out_return:
       
  2002     return ret;
       
  2003 }
       
  2004 
       
  2005 /*****************************************************************************/
       
  2006 
       
  2007 /** Add a PDO to the assignment.
       
  2008  */
       
  2009 static int ec_ioctl_sc_add_pdo(
       
  2010         ec_master_t *master, /**< EtherCAT master. */
       
  2011         void *arg, /**< ioctl() argument. */
       
  2012         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2013         )
       
  2014 {
       
  2015     ec_ioctl_config_pdo_t data;
       
  2016     ec_slave_config_t *sc;
       
  2017 
       
  2018     if (unlikely(!ctx->requested))
       
  2019         return -EPERM;
       
  2020 
       
  2021     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2022         return -EFAULT;
       
  2023 
       
  2024     if (down_interruptible(&master->master_sem))
       
  2025         return -EINTR;
       
  2026 
       
  2027     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2028         up(&master->master_sem);
       
  2029         return -ENOENT;
       
  2030     }
       
  2031 
       
  2032     up(&master->master_sem); /** \fixme sc could be invalidated */
       
  2033 
       
  2034     return ecrt_slave_config_pdo_assign_add(sc, data.sync_index, data.index);
       
  2035 }
       
  2036 
       
  2037 /*****************************************************************************/
       
  2038 
       
  2039 /** Clears the PDO assignment.
       
  2040  */
       
  2041 static int ec_ioctl_sc_clear_pdos(
       
  2042         ec_master_t *master, /**< EtherCAT master. */
       
  2043         void *arg, /**< ioctl() argument. */
       
  2044         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2045         )
       
  2046 {
       
  2047     ec_ioctl_config_pdo_t data;
       
  2048     ec_slave_config_t *sc;
       
  2049 
       
  2050     if (unlikely(!ctx->requested))
       
  2051         return -EPERM;
       
  2052 
       
  2053     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2054         return -EFAULT;
       
  2055 
       
  2056     if (down_interruptible(&master->master_sem))
       
  2057         return -EINTR;
       
  2058 
       
  2059     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2060         up(&master->master_sem);
       
  2061         return -ENOENT;
       
  2062     }
       
  2063 
       
  2064     up(&master->master_sem); /** \fixme sc could be invalidated */
       
  2065 
       
  2066     ecrt_slave_config_pdo_assign_clear(sc, data.sync_index);
       
  2067     return 0;
       
  2068 }
       
  2069 
       
  2070 /*****************************************************************************/
       
  2071 
       
  2072 /** Add an entry to a PDO's mapping.
       
  2073  */
       
  2074 static int ec_ioctl_sc_add_entry(
       
  2075         ec_master_t *master, /**< EtherCAT master. */
       
  2076         void *arg, /**< ioctl() argument. */
       
  2077         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2078         )
       
  2079 {
       
  2080     ec_ioctl_add_pdo_entry_t data;
       
  2081     ec_slave_config_t *sc;
       
  2082 
       
  2083     if (unlikely(!ctx->requested))
       
  2084         return -EPERM;
       
  2085 
       
  2086     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2087         return -EFAULT;
       
  2088 
       
  2089     if (down_interruptible(&master->master_sem))
       
  2090         return -EINTR;
       
  2091 
       
  2092     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2093         up(&master->master_sem);
       
  2094         return -ENOENT;
       
  2095     }
       
  2096 
       
  2097     up(&master->master_sem); /** \fixme sc could be invalidated */
       
  2098 
       
  2099     return ecrt_slave_config_pdo_mapping_add(sc, data.pdo_index,
       
  2100             data.entry_index, data.entry_subindex, data.entry_bit_length);
       
  2101 }
       
  2102 
       
  2103 /*****************************************************************************/
       
  2104 
       
  2105 /** Clears the mapping of a PDO.
       
  2106  */
       
  2107 static int ec_ioctl_sc_clear_entries(
       
  2108         ec_master_t *master, /**< EtherCAT master. */
       
  2109         void *arg, /**< ioctl() argument. */
       
  2110         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2111         )
       
  2112 {
       
  2113     ec_ioctl_config_pdo_t data;
       
  2114     ec_slave_config_t *sc;
       
  2115 
       
  2116     if (unlikely(!ctx->requested))
       
  2117         return -EPERM;
       
  2118 
       
  2119     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2120         return -EFAULT;
       
  2121 
       
  2122     if (down_interruptible(&master->master_sem))
       
  2123         return -EINTR;
       
  2124 
       
  2125     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2126         up(&master->master_sem);
       
  2127         return -ENOENT;
       
  2128     }
       
  2129 
       
  2130     up(&master->master_sem); /** \fixme sc could be invalidated */
       
  2131 
       
  2132     ecrt_slave_config_pdo_mapping_clear(sc, data.index);
       
  2133     return 0;
       
  2134 }
       
  2135 
       
  2136 /*****************************************************************************/
       
  2137 
       
  2138 /** Registers a PDO entry.
       
  2139  */
       
  2140 static int ec_ioctl_sc_reg_pdo_entry(
       
  2141         ec_master_t *master, /**< EtherCAT master. */
       
  2142         void *arg, /**< ioctl() argument. */
       
  2143         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2144         )
       
  2145 {
       
  2146     ec_ioctl_reg_pdo_entry_t data;
       
  2147     ec_slave_config_t *sc;
       
  2148     ec_domain_t *domain;
       
  2149     int ret;
       
  2150 
       
  2151     if (unlikely(!ctx->requested))
       
  2152         return -EPERM;
       
  2153 
       
  2154     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2155         return -EFAULT;
       
  2156 
       
  2157     if (down_interruptible(&master->master_sem))
       
  2158         return -EINTR;
       
  2159 
       
  2160     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2161         up(&master->master_sem);
       
  2162         return -ENOENT;
       
  2163     }
       
  2164 
       
  2165     if (!(domain = ec_master_find_domain(master, data.domain_index))) {
       
  2166         up(&master->master_sem);
       
  2167         return -ENOENT;
       
  2168     }
       
  2169 
       
  2170     up(&master->master_sem); /** \fixme sc or domain could be invalidated */
       
  2171 
       
  2172     ret = ecrt_slave_config_reg_pdo_entry(sc, data.entry_index,
       
  2173             data.entry_subindex, domain, &data.bit_position);
       
  2174 
       
  2175     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
  2176         return -EFAULT;
       
  2177 
       
  2178     return ret;
       
  2179 }
       
  2180 
       
  2181 /*****************************************************************************/
       
  2182 
       
  2183 /** Sets the DC AssignActivate word and the sync signal times.
       
  2184  */
       
  2185 static int ec_ioctl_sc_dc(
       
  2186         ec_master_t *master, /**< EtherCAT master. */
       
  2187         void *arg, /**< ioctl() argument. */
       
  2188         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2189         )
       
  2190 {
       
  2191     ec_ioctl_config_t data;
       
  2192     ec_slave_config_t *sc;
       
  2193 
       
  2194     if (unlikely(!ctx->requested))
       
  2195         return -EPERM;
       
  2196 
       
  2197     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2198         return -EFAULT;
       
  2199 
       
  2200     if (down_interruptible(&master->master_sem))
       
  2201         return -EINTR;
       
  2202 
       
  2203     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2204         up(&master->master_sem);
       
  2205         return -ENOENT;
       
  2206     }
       
  2207 
       
  2208     ecrt_slave_config_dc(sc, data.dc_assign_activate,
       
  2209             data.dc_sync[0].cycle_time,
       
  2210             data.dc_sync[0].shift_time,
       
  2211             data.dc_sync[1].cycle_time,
       
  2212             data.dc_sync[1].shift_time);
       
  2213 
       
  2214     up(&master->master_sem);
       
  2215 
       
  2216     return 0;
       
  2217 }
       
  2218 
       
  2219 /*****************************************************************************/
       
  2220 
       
  2221 /** Configures an SDO.
       
  2222  */
       
  2223 static int ec_ioctl_sc_sdo(
       
  2224         ec_master_t *master, /**< EtherCAT master. */
       
  2225         void *arg, /**< ioctl() argument. */
       
  2226         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2227         )
       
  2228 {
       
  2229     ec_ioctl_sc_sdo_t data;
       
  2230     ec_slave_config_t *sc;
       
  2231     uint8_t *sdo_data = NULL;
       
  2232     int ret;
       
  2233 
       
  2234     if (unlikely(!ctx->requested))
       
  2235         return -EPERM;
       
  2236 
       
  2237     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2238         return -EFAULT;
       
  2239 
       
  2240     if (!data.size)
       
  2241         return -EINVAL;
       
  2242 
       
  2243     if (!(sdo_data = kmalloc(data.size, GFP_KERNEL))) {
       
  2244         return -ENOMEM;
       
  2245     }
       
  2246 
       
  2247     if (copy_from_user(sdo_data, (void __user *) data.data, data.size)) {
       
  2248         kfree(sdo_data);
       
  2249         return -EFAULT;
       
  2250     }
       
  2251 
       
  2252     if (down_interruptible(&master->master_sem)) {
       
  2253         kfree(sdo_data);
       
  2254         return -EINTR;
       
  2255     }
       
  2256 
       
  2257     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2258         up(&master->master_sem);
       
  2259         kfree(sdo_data);
       
  2260         return -ENOENT;
       
  2261     }
       
  2262 
       
  2263     up(&master->master_sem); /** \fixme sc could be invalidated */
       
  2264 
       
  2265     if (data.complete_access) {
       
  2266         ret = ecrt_slave_config_complete_sdo(sc,
       
  2267                 data.index, sdo_data, data.size);
       
  2268     } else {
       
  2269         ret = ecrt_slave_config_sdo(sc, data.index, data.subindex, sdo_data,
       
  2270                 data.size);
       
  2271     }
       
  2272     kfree(sdo_data);
       
  2273     return ret;
       
  2274 }
       
  2275 
       
  2276 /*****************************************************************************/
       
  2277 
       
  2278 /** Create an SDO request.
       
  2279  */
       
  2280 static int ec_ioctl_sc_create_sdo_request(
       
  2281         ec_master_t *master, /**< EtherCAT master. */
       
  2282         void *arg, /**< ioctl() argument. */
       
  2283         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2284         )
       
  2285 {
       
  2286     ec_ioctl_sdo_request_t data;
       
  2287     ec_slave_config_t *sc;
       
  2288     ec_sdo_request_t *req;
       
  2289 
       
  2290     if (unlikely(!ctx->requested))
       
  2291         return -EPERM;
       
  2292 
       
  2293     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
  2294         return -EFAULT;
       
  2295     }
       
  2296 
       
  2297     data.request_index = 0;
       
  2298 
       
  2299     if (down_interruptible(&master->master_sem))
       
  2300         return -EINTR;
       
  2301 
       
  2302     sc = ec_master_get_config(master, data.config_index);
       
  2303     if (!sc) {
       
  2304         up(&master->master_sem);
       
  2305         return -ENOENT;
       
  2306     }
       
  2307 
       
  2308     list_for_each_entry(req, &sc->sdo_requests, list) {
       
  2309         data.request_index++;
       
  2310     }
       
  2311 
       
  2312     up(&master->master_sem); /** \fixme sc could be invalidated */
       
  2313 
       
  2314     req = ecrt_slave_config_create_sdo_request_err(sc, data.sdo_index,
       
  2315             data.sdo_subindex, data.size);
       
  2316     if (IS_ERR(req))
       
  2317         return PTR_ERR(req);
       
  2318 
       
  2319     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
  2320         return -EFAULT;
       
  2321 
       
  2322     return 0;
       
  2323 }
       
  2324 
       
  2325 /*****************************************************************************/
       
  2326 
       
  2327 /** Create a VoE handler.
       
  2328  */
       
  2329 static int ec_ioctl_sc_create_voe_handler(
       
  2330         ec_master_t *master, /**< EtherCAT master. */
       
  2331         void *arg, /**< ioctl() argument. */
       
  2332         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2333         )
       
  2334 {
       
  2335     ec_ioctl_voe_t data;
       
  2336     ec_slave_config_t *sc;
       
  2337     ec_voe_handler_t *voe;
       
  2338 
       
  2339     if (unlikely(!ctx->requested))
       
  2340         return -EPERM;
       
  2341 
       
  2342     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
  2343         return -EFAULT;
       
  2344     }
       
  2345 
       
  2346     data.voe_index = 0;
       
  2347 
       
  2348     if (down_interruptible(&master->master_sem))
       
  2349         return -EINTR;
       
  2350 
       
  2351     sc = ec_master_get_config(master, data.config_index);
       
  2352     if (!sc) {
       
  2353         up(&master->master_sem);
       
  2354         return -ENOENT;
       
  2355     }
       
  2356 
       
  2357     list_for_each_entry(voe, &sc->voe_handlers, list) {
       
  2358         data.voe_index++;
       
  2359     }
       
  2360 
       
  2361     up(&master->master_sem); /** \fixme sc could be invalidated */
       
  2362 
       
  2363     voe = ecrt_slave_config_create_voe_handler_err(sc, data.size);
       
  2364     if (IS_ERR(voe))
       
  2365         return PTR_ERR(voe);
       
  2366 
       
  2367     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
  2368         return -EFAULT;
       
  2369 
       
  2370     return 0;
       
  2371 }
       
  2372 
       
  2373 /*****************************************************************************/
       
  2374 
       
  2375 /** Get the slave configuration's state.
       
  2376  */
       
  2377 static int ec_ioctl_sc_state(
       
  2378         ec_master_t *master, /**< EtherCAT master. */
       
  2379         void *arg, /**< ioctl() argument. */
       
  2380         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2381         )
       
  2382 {
       
  2383     ec_ioctl_sc_state_t data;
       
  2384     const ec_slave_config_t *sc;
       
  2385     ec_slave_config_state_t state;
       
  2386 
       
  2387     if (unlikely(!ctx->requested))
       
  2388         return -EPERM;
       
  2389 
       
  2390     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
  2391         return -EFAULT;
       
  2392     }
       
  2393 
       
  2394     /* no locking of master_sem needed, because sc will not be deleted in the
       
  2395      * meantime. */
       
  2396 
       
  2397     if (!(sc = ec_master_get_config_const(master, data.config_index))) {
       
  2398         return -ENOENT;
       
  2399     }
       
  2400 
       
  2401     ecrt_slave_config_state(sc, &state);
       
  2402 
       
  2403     if (copy_to_user((void __user *) data.state, &state, sizeof(state)))
       
  2404         return -EFAULT;
       
  2405 
       
  2406     return 0;
       
  2407 }
       
  2408 
       
  2409 /*****************************************************************************/
       
  2410 
       
  2411 /** Configures an IDN.
       
  2412  */
       
  2413 static int ec_ioctl_sc_idn(
       
  2414         ec_master_t *master, /**< EtherCAT master. */
       
  2415         void *arg, /**< ioctl() argument. */
       
  2416         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2417         )
       
  2418 {
       
  2419     ec_ioctl_sc_idn_t ioctl;
       
  2420     ec_slave_config_t *sc;
       
  2421     uint8_t *data = NULL;
       
  2422     int ret;
       
  2423 
       
  2424     if (unlikely(!ctx->requested))
       
  2425         return -EPERM;
       
  2426 
       
  2427     if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl)))
       
  2428         return -EFAULT;
       
  2429 
       
  2430     if (!ioctl.size)
       
  2431         return -EINVAL;
       
  2432 
       
  2433     if (!(data = kmalloc(ioctl.size, GFP_KERNEL))) {
       
  2434         return -ENOMEM;
       
  2435     }
       
  2436 
       
  2437     if (copy_from_user(data, (void __user *) ioctl.data, ioctl.size)) {
       
  2438         kfree(data);
       
  2439         return -EFAULT;
       
  2440     }
       
  2441 
       
  2442     if (down_interruptible(&master->master_sem)) {
       
  2443         kfree(data);
       
  2444         return -EINTR;
       
  2445     }
       
  2446 
       
  2447     if (!(sc = ec_master_get_config(master, ioctl.config_index))) {
       
  2448         up(&master->master_sem);
       
  2449         kfree(data);
       
  2450         return -ENOENT;
       
  2451     }
       
  2452 
       
  2453     up(&master->master_sem); /** \fixme sc could be invalidated */
       
  2454 
       
  2455     ret = ecrt_slave_config_idn(
       
  2456             sc, ioctl.drive_no, ioctl.idn, ioctl.al_state, data, ioctl.size);
       
  2457     kfree(data);
       
  2458     return ret;
       
  2459 }
       
  2460 
       
  2461 /*****************************************************************************/
       
  2462 
       
  2463 /** Gets the domain's offset in the total process data.
       
  2464  */
       
  2465 static int ec_ioctl_domain_offset(
       
  2466         ec_master_t *master, /**< EtherCAT master. */
       
  2467         void *arg, /**< ioctl() argument. */
       
  2468         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2469         )
       
  2470 {
       
  2471     int offset = 0;
       
  2472     const ec_domain_t *domain;
       
  2473 
       
  2474     if (unlikely(!ctx->requested))
       
  2475         return -EPERM;
       
  2476 
       
  2477     if (down_interruptible(&master->master_sem)) {
       
  2478         return -EINTR;
       
  2479     }
       
  2480 
       
  2481     list_for_each_entry(domain, &master->domains, list) {
       
  2482         if (domain->index == (unsigned int) arg) {
       
  2483             up(&master->master_sem);
       
  2484             return offset;
       
  2485         }
       
  2486         offset += ecrt_domain_size(domain);
       
  2487     }
       
  2488 
       
  2489     up(&master->master_sem);
       
  2490     return -ENOENT;
       
  2491 }
       
  2492 
       
  2493 /*****************************************************************************/
       
  2494 
       
  2495 /** Process the domain.
       
  2496  */
       
  2497 static int ec_ioctl_domain_process(
       
  2498         ec_master_t *master, /**< EtherCAT master. */
       
  2499         void *arg, /**< ioctl() argument. */
       
  2500         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2501         )
       
  2502 {
       
  2503     ec_domain_t *domain;
       
  2504 
       
  2505     if (unlikely(!ctx->requested))
       
  2506         return -EPERM;
       
  2507 
       
  2508     /* no locking of master_sem needed, because domain will not be deleted in
       
  2509      * the meantime. */
       
  2510 
       
  2511     if (!(domain = ec_master_find_domain(master, (unsigned int) arg))) {
       
  2512         return -ENOENT;
       
  2513     }
       
  2514 
       
  2515     ecrt_domain_process(domain);
       
  2516     return 0;
       
  2517 }
       
  2518 
       
  2519 /*****************************************************************************/
       
  2520 
       
  2521 /** Queue the domain.
       
  2522  */
       
  2523 static int ec_ioctl_domain_queue(
       
  2524         ec_master_t *master, /**< EtherCAT master. */
       
  2525         void *arg, /**< ioctl() argument. */
       
  2526         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2527         )
       
  2528 {
       
  2529     ec_domain_t *domain;
       
  2530 
       
  2531     if (unlikely(!ctx->requested))
       
  2532         return -EPERM;
       
  2533 
       
  2534     /* no locking of master_sem needed, because domain will not be deleted in
       
  2535      * the meantime. */
       
  2536 
       
  2537     if (!(domain = ec_master_find_domain(master, (unsigned int) arg))) {
       
  2538         return -ENOENT;
       
  2539     }
       
  2540 
       
  2541     ecrt_domain_queue(domain);
       
  2542     return 0;
       
  2543 }
       
  2544 
       
  2545 /*****************************************************************************/
       
  2546 
       
  2547 /** Get the domain state.
       
  2548  */
       
  2549 static int ec_ioctl_domain_state(
       
  2550         ec_master_t *master, /**< EtherCAT master. */
       
  2551         void *arg, /**< ioctl() argument. */
       
  2552         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2553         )
       
  2554 {
       
  2555     ec_ioctl_domain_state_t data;
       
  2556     const ec_domain_t *domain;
       
  2557     ec_domain_state_t state;
       
  2558 
       
  2559     if (unlikely(!ctx->requested))
       
  2560         return -EPERM;
       
  2561 
       
  2562     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
  2563         return -EFAULT;
       
  2564     }
       
  2565 
       
  2566     /* no locking of master_sem needed, because domain will not be deleted in
       
  2567      * the meantime. */
       
  2568 
       
  2569     if (!(domain = ec_master_find_domain_const(master, data.domain_index))) {
       
  2570         return -ENOENT;
       
  2571     }
       
  2572 
       
  2573     ecrt_domain_state(domain, &state);
       
  2574 
       
  2575     if (copy_to_user((void __user *) data.state, &state, sizeof(state)))
       
  2576         return -EFAULT;
       
  2577 
       
  2578     return 0;
       
  2579 }
       
  2580 
       
  2581 /*****************************************************************************/
       
  2582 
       
  2583 /** Sets an SDO request's timeout.
       
  2584  */
       
  2585 static int ec_ioctl_sdo_request_timeout(
       
  2586         ec_master_t *master, /**< EtherCAT master. */
       
  2587         void *arg, /**< ioctl() argument. */
       
  2588         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2589         )
       
  2590 {
       
  2591     ec_ioctl_sdo_request_t data;
       
  2592     ec_slave_config_t *sc;
       
  2593     ec_sdo_request_t *req;
       
  2594 
       
  2595     if (unlikely(!ctx->requested))
       
  2596         return -EPERM;
       
  2597 
       
  2598     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2599         return -EFAULT;
       
  2600 
       
  2601     /* no locking of master_sem needed, because neither sc nor req will not be
       
  2602      * deleted in the meantime. */
       
  2603 
       
  2604     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2605         return -ENOENT;
       
  2606     }
       
  2607 
       
  2608     if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) {
       
  2609         return -ENOENT;
       
  2610     }
       
  2611 
       
  2612     ecrt_sdo_request_timeout(req, data.timeout);
       
  2613     return 0;
       
  2614 }
       
  2615 
       
  2616 /*****************************************************************************/
       
  2617 
       
  2618 /** Gets an SDO request's state.
       
  2619  */
       
  2620 static int ec_ioctl_sdo_request_state(
       
  2621         ec_master_t *master, /**< EtherCAT master. */
       
  2622         void *arg, /**< ioctl() argument. */
       
  2623         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2624         )
       
  2625 {
       
  2626     ec_ioctl_sdo_request_t data;
       
  2627     ec_slave_config_t *sc;
       
  2628     ec_sdo_request_t *req;
       
  2629 
       
  2630     if (unlikely(!ctx->requested))
       
  2631         return -EPERM;
       
  2632 
       
  2633     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2634         return -EFAULT;
       
  2635 
       
  2636     /* no locking of master_sem needed, because neither sc nor req will not be
       
  2637      * deleted in the meantime. */
       
  2638 
       
  2639     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2640         return -ENOENT;
       
  2641     }
       
  2642 
       
  2643     if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) {
       
  2644         return -ENOENT;
       
  2645     }
       
  2646 
       
  2647     data.state = ecrt_sdo_request_state(req);
       
  2648     if (data.state == EC_REQUEST_SUCCESS && req->dir == EC_DIR_INPUT)
       
  2649         data.size = ecrt_sdo_request_data_size(req);
       
  2650     else
       
  2651         data.size = 0;
       
  2652 
       
  2653     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
  2654         return -EFAULT;
       
  2655 
       
  2656     return 0;
       
  2657 }
       
  2658 
       
  2659 /*****************************************************************************/
       
  2660 
       
  2661 /** Starts an SDO read operation.
       
  2662  */
       
  2663 static int ec_ioctl_sdo_request_read(
       
  2664         ec_master_t *master, /**< EtherCAT master. */
       
  2665         void *arg, /**< ioctl() argument. */
       
  2666         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2667         )
       
  2668 {
       
  2669     ec_ioctl_sdo_request_t data;
       
  2670     ec_slave_config_t *sc;
       
  2671     ec_sdo_request_t *req;
       
  2672 
       
  2673     if (unlikely(!ctx->requested))
       
  2674         return -EPERM;
       
  2675 
       
  2676     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2677         return -EFAULT;
       
  2678 
       
  2679     /* no locking of master_sem needed, because neither sc nor req will not be
       
  2680      * deleted in the meantime. */
       
  2681 
       
  2682     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2683         return -ENOENT;
       
  2684     }
       
  2685 
       
  2686     if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) {
       
  2687         return -ENOENT;
       
  2688     }
       
  2689 
       
  2690     ecrt_sdo_request_read(req);
       
  2691     return 0;
       
  2692 }
       
  2693 
       
  2694 /*****************************************************************************/
       
  2695 
       
  2696 /** Starts an SDO write operation.
       
  2697  */
       
  2698 static int ec_ioctl_sdo_request_write(
       
  2699         ec_master_t *master, /**< EtherCAT master. */
       
  2700         void *arg, /**< ioctl() argument. */
       
  2701         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2702         )
       
  2703 {
       
  2704     ec_ioctl_sdo_request_t data;
       
  2705     ec_slave_config_t *sc;
       
  2706     ec_sdo_request_t *req;
       
  2707     int ret;
       
  2708 
       
  2709     if (unlikely(!ctx->requested))
       
  2710         return -EPERM;
       
  2711 
       
  2712     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2713         return -EFAULT;
       
  2714 
       
  2715     if (!data.size) {
       
  2716         EC_MASTER_ERR(master, "SDO download: Data size may not be zero!\n");
       
  2717         return -EINVAL;
       
  2718     }
       
  2719 
       
  2720     /* no locking of master_sem needed, because neither sc nor req will not be
       
  2721      * deleted in the meantime. */
       
  2722 
       
  2723     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2724         return -ENOENT;
       
  2725     }
       
  2726 
       
  2727     if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) {
       
  2728         return -ENOENT;
       
  2729     }
       
  2730 
       
  2731     ret = ec_sdo_request_alloc(req, data.size);
       
  2732     if (ret)
       
  2733         return ret;
       
  2734 
       
  2735     if (copy_from_user(req->data, (void __user *) data.data, data.size))
       
  2736         return -EFAULT;
       
  2737 
       
  2738     req->data_size = data.size;
       
  2739     ecrt_sdo_request_write(req);
       
  2740     return 0;
       
  2741 }
       
  2742 
       
  2743 /*****************************************************************************/
       
  2744 
       
  2745 /** Read SDO data.
       
  2746  */
       
  2747 static int ec_ioctl_sdo_request_data(
       
  2748         ec_master_t *master, /**< EtherCAT master. */
       
  2749         void *arg, /**< ioctl() argument. */
       
  2750         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2751         )
       
  2752 {
       
  2753     ec_ioctl_sdo_request_t data;
       
  2754     ec_slave_config_t *sc;
       
  2755     ec_sdo_request_t *req;
       
  2756 
       
  2757     if (unlikely(!ctx->requested))
       
  2758         return -EPERM;
       
  2759 
       
  2760     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2761         return -EFAULT;
       
  2762 
       
  2763     /* no locking of master_sem needed, because neither sc nor req will not be
       
  2764      * deleted in the meantime. */
       
  2765 
       
  2766     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2767         return -ENOENT;
       
  2768     }
       
  2769 
       
  2770     if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) {
       
  2771         return -ENOENT;
       
  2772     }
       
  2773 
       
  2774     if (copy_to_user((void __user *) data.data, ecrt_sdo_request_data(req),
       
  2775                 ecrt_sdo_request_data_size(req)))
       
  2776         return -EFAULT;
       
  2777 
       
  2778     return 0;
       
  2779 }
       
  2780 
       
  2781 /*****************************************************************************/
       
  2782 
       
  2783 /** Sets the VoE send header.
       
  2784  */
       
  2785 static int ec_ioctl_voe_send_header(
       
  2786         ec_master_t *master, /**< EtherCAT master. */
       
  2787         void *arg, /**< ioctl() argument. */
       
  2788         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2789         )
       
  2790 {
       
  2791     ec_ioctl_voe_t data;
       
  2792     ec_slave_config_t *sc;
       
  2793     ec_voe_handler_t *voe;
       
  2794     uint32_t vendor_id;
       
  2795     uint16_t vendor_type;
       
  2796 
       
  2797     if (unlikely(!ctx->requested))
       
  2798         return -EPERM;
       
  2799 
       
  2800     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2801         return -EFAULT;
       
  2802 
       
  2803     if (get_user(vendor_id, data.vendor_id))
       
  2804         return -EFAULT;
       
  2805 
       
  2806     if (get_user(vendor_type, data.vendor_type))
       
  2807         return -EFAULT;
       
  2808 
       
  2809     /* no locking of master_sem needed, because neither sc nor voe will not be
       
  2810      * deleted in the meantime. */
       
  2811 
       
  2812     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2813         return -ENOENT;
       
  2814     }
       
  2815 
       
  2816     if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) {
       
  2817         return -ENOENT;
       
  2818     }
       
  2819 
       
  2820     ecrt_voe_handler_send_header(voe, vendor_id, vendor_type);
       
  2821     return 0;
       
  2822 }
       
  2823 
       
  2824 /*****************************************************************************/
       
  2825 
       
  2826 /** Gets the received VoE header.
       
  2827  */
       
  2828 static int ec_ioctl_voe_rec_header(
       
  2829         ec_master_t *master, /**< EtherCAT master. */
       
  2830         void *arg, /**< ioctl() argument. */
       
  2831         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2832         )
       
  2833 {
       
  2834     ec_ioctl_voe_t data;
       
  2835     ec_slave_config_t *sc;
       
  2836     ec_voe_handler_t *voe;
       
  2837     uint32_t vendor_id;
       
  2838     uint16_t vendor_type;
       
  2839 
       
  2840     if (unlikely(!ctx->requested))
       
  2841         return -EPERM;
       
  2842 
       
  2843     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2844         return -EFAULT;
       
  2845 
       
  2846     /* no locking of master_sem needed, because neither sc nor voe will not be
       
  2847      * deleted in the meantime. */
       
  2848 
       
  2849     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2850         return -ENOENT;
       
  2851     }
       
  2852 
       
  2853     if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) {
       
  2854         return -ENOENT;
       
  2855     }
       
  2856 
       
  2857     ecrt_voe_handler_received_header(voe, &vendor_id, &vendor_type);
       
  2858 
       
  2859     if (likely(data.vendor_id))
       
  2860         if (put_user(vendor_id, data.vendor_id))
       
  2861             return -EFAULT;
       
  2862 
       
  2863     if (likely(data.vendor_type))
       
  2864         if (put_user(vendor_type, data.vendor_type))
       
  2865             return -EFAULT;
       
  2866 
       
  2867     return 0;
       
  2868 }
       
  2869 
       
  2870 /*****************************************************************************/
       
  2871 
       
  2872 /** Starts a VoE read operation.
       
  2873  */
       
  2874 static int ec_ioctl_voe_read(
       
  2875         ec_master_t *master, /**< EtherCAT master. */
       
  2876         void *arg, /**< ioctl() argument. */
       
  2877         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2878         )
       
  2879 {
       
  2880     ec_ioctl_voe_t data;
       
  2881     ec_slave_config_t *sc;
       
  2882     ec_voe_handler_t *voe;
       
  2883 
       
  2884     if (unlikely(!ctx->requested))
       
  2885         return -EPERM;
       
  2886 
       
  2887     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2888         return -EFAULT;
       
  2889 
       
  2890     /* no locking of master_sem needed, because neither sc nor voe will not be
       
  2891      * deleted in the meantime. */
       
  2892 
       
  2893     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2894         return -ENOENT;
       
  2895     }
       
  2896 
       
  2897     if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) {
       
  2898         return -ENOENT;
       
  2899     }
       
  2900 
       
  2901     ecrt_voe_handler_read(voe);
       
  2902     return 0;
       
  2903 }
       
  2904 
       
  2905 /*****************************************************************************/
       
  2906 
       
  2907 /** Starts a VoE read operation without sending a sync message first.
       
  2908  */
       
  2909 static int ec_ioctl_voe_read_nosync(
       
  2910         ec_master_t *master, /**< EtherCAT master. */
       
  2911         void *arg, /**< ioctl() argument. */
       
  2912         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2913         )
       
  2914 {
       
  2915     ec_ioctl_voe_t data;
       
  2916     ec_slave_config_t *sc;
       
  2917     ec_voe_handler_t *voe;
       
  2918 
       
  2919     if (unlikely(!ctx->requested))
       
  2920         return -EPERM;
       
  2921 
       
  2922     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2923         return -EFAULT;
       
  2924 
       
  2925     /* no locking of master_sem needed, because neither sc nor voe will not be
       
  2926      * deleted in the meantime. */
       
  2927 
       
  2928     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2929         return -ENOENT;
       
  2930     }
       
  2931 
       
  2932     if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) {
       
  2933         return -ENOENT;
       
  2934     }
       
  2935 
       
  2936     ecrt_voe_handler_read_nosync(voe);
       
  2937     return 0;
       
  2938 }
       
  2939 
       
  2940 /*****************************************************************************/
       
  2941 
       
  2942 /** Starts a VoE write operation.
       
  2943  */
       
  2944 static int ec_ioctl_voe_write(
       
  2945         ec_master_t *master, /**< EtherCAT master. */
       
  2946         void *arg, /**< ioctl() argument. */
       
  2947         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2948         )
       
  2949 {
       
  2950     ec_ioctl_voe_t data;
       
  2951     ec_slave_config_t *sc;
       
  2952     ec_voe_handler_t *voe;
       
  2953 
       
  2954     if (unlikely(!ctx->requested))
       
  2955         return -EPERM;
       
  2956 
       
  2957     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  2958         return -EFAULT;
       
  2959 
       
  2960     /* no locking of master_sem needed, because neither sc nor voe will not be
       
  2961      * deleted in the meantime. */
       
  2962 
       
  2963     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  2964         return -ENOENT;
       
  2965     }
       
  2966 
       
  2967     if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) {
       
  2968         return -ENOENT;
       
  2969     }
       
  2970 
       
  2971     if (data.size) {
       
  2972         if (data.size > ec_voe_handler_mem_size(voe))
       
  2973             return -EOVERFLOW;
       
  2974 
       
  2975         if (copy_from_user(ecrt_voe_handler_data(voe),
       
  2976                     (void __user *) data.data, data.size))
       
  2977             return -EFAULT;
       
  2978     }
       
  2979 
       
  2980     ecrt_voe_handler_write(voe, data.size);
       
  2981     return 0;
       
  2982 }
       
  2983 
       
  2984 /*****************************************************************************/
       
  2985 
       
  2986 /** Executes the VoE state machine.
       
  2987  */
       
  2988 static int ec_ioctl_voe_exec(
       
  2989         ec_master_t *master, /**< EtherCAT master. */
       
  2990         void *arg, /**< ioctl() argument. */
       
  2991         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  2992         )
       
  2993 {
       
  2994     ec_ioctl_voe_t data;
       
  2995     ec_slave_config_t *sc;
       
  2996     ec_voe_handler_t *voe;
       
  2997 
       
  2998     if (unlikely(!ctx->requested))
       
  2999         return -EPERM;
       
  3000 
       
  3001     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  3002         return -EFAULT;
       
  3003 
       
  3004     /* no locking of master_sem needed, because neither sc nor voe will not be
       
  3005      * deleted in the meantime. */
       
  3006 
       
  3007     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  3008         return -ENOENT;
       
  3009     }
       
  3010 
       
  3011     if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) {
       
  3012         return -ENOENT;
       
  3013     }
       
  3014 
       
  3015     data.state = ecrt_voe_handler_execute(voe);
       
  3016     if (data.state == EC_REQUEST_SUCCESS && voe->dir == EC_DIR_INPUT)
       
  3017         data.size = ecrt_voe_handler_data_size(voe);
       
  3018     else
       
  3019         data.size = 0;
       
  3020 
       
  3021     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
       
  3022         return -EFAULT;
       
  3023 
       
  3024     return 0;
       
  3025 }
       
  3026 
       
  3027 /*****************************************************************************/
       
  3028 
       
  3029 /** Reads the received VoE data.
       
  3030  */
       
  3031 static int ec_ioctl_voe_data(
       
  3032         ec_master_t *master, /**< EtherCAT master. */
       
  3033         void *arg, /**< ioctl() argument. */
       
  3034         ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
       
  3035         )
       
  3036 {
       
  3037     ec_ioctl_voe_t data;
       
  3038     ec_slave_config_t *sc;
       
  3039     ec_voe_handler_t *voe;
       
  3040 
       
  3041     if (unlikely(!ctx->requested))
       
  3042         return -EPERM;
       
  3043 
       
  3044     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
       
  3045         return -EFAULT;
       
  3046 
       
  3047     /* no locking of master_sem needed, because neither sc nor voe will not be
       
  3048      * deleted in the meantime. */
       
  3049 
       
  3050     if (!(sc = ec_master_get_config(master, data.config_index))) {
       
  3051         return -ENOENT;
       
  3052     }
       
  3053 
       
  3054     if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) {
       
  3055         return -ENOENT;
       
  3056     }
       
  3057 
       
  3058     if (copy_to_user((void __user *) data.data, ecrt_voe_handler_data(voe),
       
  3059                 ecrt_voe_handler_data_size(voe)))
       
  3060         return -EFAULT;
       
  3061 
       
  3062     return 0;
       
  3063 }
       
  3064 
       
  3065 /*****************************************************************************/
       
  3066 
       
  3067 /** Read a file from a slave via FoE.
       
  3068  */
       
  3069 static int ec_ioctl_slave_foe_read(
       
  3070         ec_master_t *master, /**< EtherCAT master. */
       
  3071         void *arg /**< ioctl() argument. */
       
  3072         )
       
  3073 {
       
  3074     ec_ioctl_slave_foe_t data;
       
  3075     ec_master_foe_request_t request;
       
  3076     int retval;
       
  3077 
       
  3078     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
  3079         return -EFAULT;
       
  3080     }
       
  3081 
       
  3082     ec_foe_request_init(&request.req, data.file_name);
       
  3083     ec_foe_request_read(&request.req);
       
  3084     ec_foe_request_alloc(&request.req, 10000); // FIXME
       
  3085 
       
  3086     if (down_interruptible(&master->master_sem)) {
       
  3087         ec_foe_request_clear(&request.req);
       
  3088         return -EINTR;
       
  3089     }
       
  3090 
       
  3091     if (!(request.slave = ec_master_find_slave(
       
  3092                     master, 0, data.slave_position))) {
       
  3093         up(&master->master_sem);
       
  3094         ec_foe_request_clear(&request.req);
       
  3095         EC_MASTER_ERR(master, "Slave %u does not exist!\n",
       
  3096                 data.slave_position);
       
  3097         return -EINVAL;
       
  3098     }
       
  3099 
       
  3100     // schedule request.
       
  3101     list_add_tail(&request.list, &request.slave->foe_requests);
       
  3102 
       
  3103     up(&master->master_sem);
       
  3104 
       
  3105     EC_SLAVE_DBG(request.slave, 1, "Scheduled FoE read request.\n");
       
  3106 
       
  3107     // wait for processing through FSM
       
  3108     if (wait_event_interruptible(request.slave->foe_queue,
       
  3109                 request.req.state != EC_INT_REQUEST_QUEUED)) {
       
  3110         // interrupted by signal
       
  3111         down(&master->master_sem);
       
  3112         if (request.req.state == EC_INT_REQUEST_QUEUED) {
       
  3113             list_del(&request.list);
       
  3114             up(&master->master_sem);
       
  3115             ec_foe_request_clear(&request.req);
       
  3116             return -EINTR;
       
  3117         }
       
  3118         // request already processing: interrupt not possible.
       
  3119         up(&master->master_sem);
       
  3120     }
       
  3121 
       
  3122     // wait until master FSM has finished processing
       
  3123     wait_event(request.slave->foe_queue,
       
  3124             request.req.state != EC_INT_REQUEST_BUSY);
       
  3125 
       
  3126     data.result = request.req.result;
       
  3127     data.error_code = request.req.error_code;
       
  3128 
       
  3129     EC_SLAVE_DBG(request.slave, 1, "Read %zd bytes via FoE"
       
  3130             " (result = 0x%x).\n", request.req.data_size, request.req.result);
       
  3131 
       
  3132     if (request.req.state != EC_INT_REQUEST_SUCCESS) {
       
  3133         data.data_size = 0;
       
  3134         retval = -EIO;
       
  3135     } else {
       
  3136         if (request.req.data_size > data.buffer_size) {
       
  3137             EC_MASTER_ERR(master, "Buffer too small.\n");
       
  3138             ec_foe_request_clear(&request.req);
       
  3139             return -EOVERFLOW;
       
  3140         }
       
  3141         data.data_size = request.req.data_size;
       
  3142         if (copy_to_user((void __user *) data.buffer,
       
  3143                     request.req.buffer, data.data_size)) {
       
  3144             ec_foe_request_clear(&request.req);
       
  3145             return -EFAULT;
       
  3146         }
       
  3147         retval = 0;
       
  3148     }
       
  3149 
       
  3150     if (__copy_to_user((void __user *) arg, &data, sizeof(data))) {
       
  3151         retval = -EFAULT;
       
  3152     }
       
  3153 
       
  3154     EC_SLAVE_DBG(request.slave, 1, "Finished FoE read request.\n");
       
  3155 
       
  3156     ec_foe_request_clear(&request.req);
       
  3157 
       
  3158     return retval;
       
  3159 }
       
  3160 
       
  3161 /*****************************************************************************/
       
  3162 
       
  3163 /** Write a file to a slave via FoE
       
  3164  */
       
  3165 static int ec_ioctl_slave_foe_write(
       
  3166         ec_master_t *master, /**< EtherCAT master. */
       
  3167         void *arg /**< ioctl() argument. */
       
  3168         )
       
  3169 {
       
  3170     ec_ioctl_slave_foe_t data;
       
  3171     ec_master_foe_request_t request;
       
  3172     int retval;
       
  3173 
       
  3174     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
       
  3175         return -EFAULT;
       
  3176     }
       
  3177 
       
  3178     INIT_LIST_HEAD(&request.list);
       
  3179 
       
  3180     ec_foe_request_init(&request.req, data.file_name);
       
  3181 
       
  3182     if (ec_foe_request_alloc(&request.req, data.buffer_size)) {
       
  3183         ec_foe_request_clear(&request.req);
       
  3184         return -ENOMEM;
       
  3185     }
       
  3186     if (copy_from_user(request.req.buffer,
       
  3187                 (void __user *) data.buffer, data.buffer_size)) {
       
  3188         ec_foe_request_clear(&request.req);
       
  3189         return -EFAULT;
       
  3190     }
       
  3191     request.req.data_size = data.buffer_size;
       
  3192     ec_foe_request_write(&request.req);
       
  3193 
       
  3194     if (down_interruptible(&master->master_sem)) {
       
  3195         ec_foe_request_clear(&request.req);
       
  3196         return -EINTR;
       
  3197     }
       
  3198 
       
  3199     if (!(request.slave = ec_master_find_slave(
       
  3200                     master, 0, data.slave_position))) {
       
  3201         up(&master->master_sem);
       
  3202         EC_MASTER_ERR(master, "Slave %u does not exist!\n",
       
  3203                 data.slave_position);
       
  3204         ec_foe_request_clear(&request.req);
       
  3205         return -EINVAL;
       
  3206     }
       
  3207 
       
  3208     EC_SLAVE_DBG(request.slave, 1, "Scheduling FoE write request.\n");
       
  3209 
       
  3210     // schedule FoE write request.
       
  3211     list_add_tail(&request.list, &request.slave->foe_requests);
       
  3212 
       
  3213     up(&master->master_sem);
       
  3214 
       
  3215     // wait for processing through FSM
       
  3216     if (wait_event_interruptible(request.slave->foe_queue,
       
  3217                 request.req.state != EC_INT_REQUEST_QUEUED)) {
       
  3218         // interrupted by signal
       
  3219         down(&master->master_sem);
       
  3220         if (request.req.state == EC_INT_REQUEST_QUEUED) {
       
  3221             // abort request
       
  3222             list_del(&request.list);
       
  3223             up(&master->master_sem);
       
  3224             ec_foe_request_clear(&request.req);
       
  3225             return -EINTR;
       
  3226         }
       
  3227         up(&master->master_sem);
       
  3228     }
       
  3229 
       
  3230     // wait until master FSM has finished processing
       
  3231     wait_event(request.slave->foe_queue,
       
  3232             request.req.state != EC_INT_REQUEST_BUSY);
       
  3233 
       
  3234     data.result = request.req.result;
       
  3235     data.error_code = request.req.error_code;
       
  3236 
       
  3237     retval = request.req.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
       
  3238 
       
  3239     if (__copy_to_user((void __user *) arg, &data, sizeof(data))) {
       
  3240         retval = -EFAULT;
       
  3241     }
       
  3242 
       
  3243     ec_foe_request_clear(&request.req);
       
  3244 
       
  3245     EC_SLAVE_DBG(request.slave, 1, "Finished FoE write request.\n");
       
  3246 
       
  3247     return retval;
       
  3248 }
       
  3249 
       
  3250 /*****************************************************************************/
       
  3251 
       
  3252 /** Read an SoE IDN.
       
  3253  */
       
  3254 static int ec_ioctl_slave_soe_read(
       
  3255         ec_master_t *master, /**< EtherCAT master. */
       
  3256         void *arg /**< ioctl() argument. */
       
  3257         )
       
  3258 {
       
  3259     ec_ioctl_slave_soe_read_t ioctl;
       
  3260     u8 *data;
       
  3261     int retval;
       
  3262 
       
  3263     if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl))) {
       
  3264         return -EFAULT;
       
  3265     }
       
  3266 
       
  3267     data = kmalloc(ioctl.mem_size, GFP_KERNEL);
       
  3268     if (!data) {
       
  3269         EC_MASTER_ERR(master, "Failed to allocate %u bytes of IDN data.\n",
       
  3270                 ioctl.mem_size);
       
  3271         return -ENOMEM;
       
  3272     }
       
  3273 
       
  3274     retval = ecrt_master_read_idn(master, ioctl.slave_position,
       
  3275             ioctl.drive_no, ioctl.idn, data, ioctl.mem_size, &ioctl.data_size,
       
  3276             &ioctl.error_code);
       
  3277     if (retval) {
       
  3278         kfree(data);
       
  3279         return retval;
       
  3280     }
       
  3281 
       
  3282     if (copy_to_user((void __user *) ioctl.data,
       
  3283                 data, ioctl.data_size)) {
       
  3284         kfree(data);
       
  3285         return -EFAULT;
       
  3286     }
       
  3287     kfree(data);
       
  3288 
       
  3289     if (__copy_to_user((void __user *) arg, &ioctl, sizeof(ioctl))) {
       
  3290         retval = -EFAULT;
       
  3291     }
       
  3292 
       
  3293     EC_MASTER_DBG(master, 1, "Finished SoE read request.\n");
       
  3294     return retval;
       
  3295 }
       
  3296 
       
  3297 /*****************************************************************************/
       
  3298 
       
  3299 /** Write an IDN to a slave via SoE.
       
  3300  */
       
  3301 static int ec_ioctl_slave_soe_write(
       
  3302         ec_master_t *master, /**< EtherCAT master. */
       
  3303         void *arg /**< ioctl() argument. */
       
  3304         )
       
  3305 {
       
  3306     ec_ioctl_slave_soe_write_t ioctl;
       
  3307     u8 *data;
       
  3308     int retval;
       
  3309 
       
  3310     if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl))) {
       
  3311         return -EFAULT;
       
  3312     }
       
  3313 
       
  3314     data = kmalloc(ioctl.data_size, GFP_KERNEL);
       
  3315     if (!data) {
       
  3316         EC_MASTER_ERR(master, "Failed to allocate %zu bytes of IDN data.\n",
       
  3317                 ioctl.data_size);
       
  3318         return -ENOMEM;
       
  3319     }
       
  3320     if (copy_from_user(data, (void __user *) ioctl.data, ioctl.data_size)) {
       
  3321         kfree(data);
       
  3322         return -EFAULT;
       
  3323     }
       
  3324 
       
  3325     retval = ecrt_master_write_idn(master, ioctl.slave_position,
       
  3326             ioctl.drive_no, ioctl.idn, data, ioctl.data_size,
       
  3327             &ioctl.error_code);
       
  3328     kfree(data);
       
  3329     if (retval) {
       
  3330         return retval;
       
  3331     }
       
  3332 
       
  3333     if (__copy_to_user((void __user *) arg, &ioctl, sizeof(ioctl))) {
       
  3334         retval = -EFAULT;
       
  3335     }
       
  3336 
       
  3337     EC_MASTER_DBG(master, 1, "Finished SoE write request.\n");
       
  3338     return retval;
       
  3339 }
       
  3340 
       
  3341 /*****************************************************************************/
       
  3342 
       
  3343 #ifdef EC_IOCTL_RTDM
       
  3344 #define EC_IOCTL ec_ioctl_rtdm
       
  3345 #else
       
  3346 #define EC_IOCTL ec_ioctl
       
  3347 #endif
       
  3348 
       
  3349 /** Called when an ioctl() command is issued.
       
  3350  */
       
  3351 long EC_IOCTL(ec_master_t *master, ec_ioctl_context_t *ctx,
       
  3352 		unsigned int cmd, void *arg)
       
  3353 {
       
  3354 #if DEBUG_LATENCY
       
  3355     cycles_t a = get_cycles(), b;
       
  3356     unsigned int t;
       
  3357 #endif
       
  3358     int ret;
       
  3359 
       
  3360     switch (cmd) {
       
  3361         case EC_IOCTL_MODULE:
       
  3362             ret = ec_ioctl_module(arg);
       
  3363             break;
       
  3364         case EC_IOCTL_MASTER:
       
  3365             ret = ec_ioctl_master(master, arg);
       
  3366             break;
       
  3367         case EC_IOCTL_SLAVE:
       
  3368             ret = ec_ioctl_slave(master, arg);
       
  3369             break;
       
  3370         case EC_IOCTL_SLAVE_SYNC:
       
  3371             ret = ec_ioctl_slave_sync(master, arg);
       
  3372             break;
       
  3373         case EC_IOCTL_SLAVE_SYNC_PDO:
       
  3374             ret = ec_ioctl_slave_sync_pdo(master, arg);
       
  3375             break;
       
  3376         case EC_IOCTL_SLAVE_SYNC_PDO_ENTRY:
       
  3377             ret = ec_ioctl_slave_sync_pdo_entry(master, arg);
       
  3378             break;
       
  3379         case EC_IOCTL_DOMAIN:
       
  3380             ret = ec_ioctl_domain(master, arg);
       
  3381             break;
       
  3382         case EC_IOCTL_DOMAIN_FMMU:
       
  3383             ret = ec_ioctl_domain_fmmu(master, arg);
       
  3384             break;
       
  3385         case EC_IOCTL_DOMAIN_DATA:
       
  3386             ret = ec_ioctl_domain_data(master, arg);
       
  3387             break;
       
  3388         case EC_IOCTL_MASTER_DEBUG:
       
  3389             if (!ctx->writable) {
       
  3390                 ret = -EPERM;
       
  3391                 break;
       
  3392             }
       
  3393             ret = ec_ioctl_master_debug(master, arg);
       
  3394             break;
       
  3395         case EC_IOCTL_MASTER_RESCAN:
       
  3396             if (!ctx->writable) {
       
  3397                 ret = -EPERM;
       
  3398                 break;
       
  3399             }
       
  3400             ret = ec_ioctl_master_rescan(master, arg);
       
  3401             break;
       
  3402         case EC_IOCTL_SLAVE_STATE:
       
  3403             if (!ctx->writable) {
       
  3404                 ret = -EPERM;
       
  3405                 break;
       
  3406             }
       
  3407             ret = ec_ioctl_slave_state(master, arg);
       
  3408             break;
       
  3409         case EC_IOCTL_SLAVE_SDO:
       
  3410             ret = ec_ioctl_slave_sdo(master, arg);
       
  3411             break;
       
  3412         case EC_IOCTL_SLAVE_SDO_ENTRY:
       
  3413             ret = ec_ioctl_slave_sdo_entry(master, arg);
       
  3414             break;
       
  3415         case EC_IOCTL_SLAVE_SDO_UPLOAD:
       
  3416             ret = ec_ioctl_slave_sdo_upload(master, arg);
       
  3417             break;
       
  3418         case EC_IOCTL_SLAVE_SDO_DOWNLOAD:
       
  3419             if (!ctx->writable) {
       
  3420                 ret = -EPERM;
       
  3421                 break;
       
  3422             }
       
  3423             ret = ec_ioctl_slave_sdo_download(master, arg);
       
  3424             break;
       
  3425         case EC_IOCTL_SLAVE_SII_READ:
       
  3426             ret = ec_ioctl_slave_sii_read(master, arg);
       
  3427             break;
       
  3428         case EC_IOCTL_SLAVE_SII_WRITE:
       
  3429             if (!ctx->writable) {
       
  3430                 ret = -EPERM;
       
  3431                 break;
       
  3432             }
       
  3433             ret = ec_ioctl_slave_sii_write(master, arg);
       
  3434             break;
       
  3435         case EC_IOCTL_SLAVE_REG_READ:
       
  3436             ret = ec_ioctl_slave_reg_read(master, arg);
       
  3437             break;
       
  3438         case EC_IOCTL_SLAVE_REG_WRITE:
       
  3439             if (!ctx->writable) {
       
  3440                 ret = -EPERM;
       
  3441                 break;
       
  3442             }
       
  3443             ret = ec_ioctl_slave_reg_write(master, arg);
       
  3444             break;
       
  3445         case EC_IOCTL_SLAVE_FOE_READ:
       
  3446             ret = ec_ioctl_slave_foe_read(master, arg);
       
  3447             break;
       
  3448         case EC_IOCTL_SLAVE_FOE_WRITE:
       
  3449             if (!ctx->writable) {
       
  3450                 ret = -EPERM;
       
  3451                 break;
       
  3452             }
       
  3453             ret = ec_ioctl_slave_foe_write(master, arg);
       
  3454             break;
       
  3455         case EC_IOCTL_SLAVE_SOE_READ:
       
  3456             ret = ec_ioctl_slave_soe_read(master, arg);
       
  3457             break;
       
  3458         case EC_IOCTL_SLAVE_SOE_WRITE:
       
  3459             if (!ctx->writable) {
       
  3460                 ret = -EPERM;
       
  3461                 break;
       
  3462             }
       
  3463             ret = ec_ioctl_slave_soe_write(master, arg);
       
  3464             break;
       
  3465         case EC_IOCTL_CONFIG:
       
  3466             ret = ec_ioctl_config(master, arg);
       
  3467             break;
       
  3468         case EC_IOCTL_CONFIG_PDO:
       
  3469             ret = ec_ioctl_config_pdo(master, arg);
       
  3470             break;
       
  3471         case EC_IOCTL_CONFIG_PDO_ENTRY:
       
  3472             ret = ec_ioctl_config_pdo_entry(master, arg);
       
  3473             break;
       
  3474         case EC_IOCTL_CONFIG_SDO:
       
  3475             ret = ec_ioctl_config_sdo(master, arg);
       
  3476             break;
       
  3477         case EC_IOCTL_CONFIG_IDN:
       
  3478             ret = ec_ioctl_config_idn(master, arg);
       
  3479             break;
       
  3480 #ifdef EC_EOE
       
  3481         case EC_IOCTL_EOE_HANDLER:
       
  3482             ret = ec_ioctl_eoe_handler(master, arg);
       
  3483             break;
       
  3484 #endif
       
  3485         case EC_IOCTL_REQUEST:
       
  3486             if (!ctx->writable) {
       
  3487                 ret = -EPERM;
       
  3488                 break;
       
  3489             }
       
  3490             ret = ec_ioctl_request(master, arg, ctx);
       
  3491             break;
       
  3492         case EC_IOCTL_CREATE_DOMAIN:
       
  3493             if (!ctx->writable) {
       
  3494                 ret = -EPERM;
       
  3495                 break;
       
  3496             }
       
  3497             ret = ec_ioctl_create_domain(master, arg, ctx);
       
  3498             break;
       
  3499         case EC_IOCTL_CREATE_SLAVE_CONFIG:
       
  3500             if (!ctx->writable) {
       
  3501                 ret = -EPERM;
       
  3502                 break;
       
  3503             }
       
  3504             ret = ec_ioctl_create_slave_config(master, arg, ctx);
       
  3505             break;
       
  3506         case EC_IOCTL_ACTIVATE:
       
  3507             if (!ctx->writable) {
       
  3508                 ret = -EPERM;
       
  3509                 break;
       
  3510             }
       
  3511             ret = ec_ioctl_activate(master, arg, ctx);
       
  3512             break;
       
  3513         case EC_IOCTL_DEACTIVATE:
       
  3514             if (!ctx->writable) {
       
  3515                 ret = -EPERM;
       
  3516                 break;
       
  3517             }
       
  3518             ret = ec_ioctl_deactivate(master, arg, ctx);
       
  3519             break;
       
  3520         case EC_IOCTL_SEND:
       
  3521             if (!ctx->writable) {
       
  3522                 ret = -EPERM;
       
  3523                 break;
       
  3524             }
       
  3525             ret = ec_ioctl_send(master, arg, ctx);
       
  3526             break;
       
  3527         case EC_IOCTL_RECEIVE:
       
  3528             if (!ctx->writable) {
       
  3529                 ret = -EPERM;
       
  3530                 break;
       
  3531             }
       
  3532             ret = ec_ioctl_receive(master, arg, ctx);
       
  3533             break;
       
  3534         case EC_IOCTL_MASTER_STATE:
       
  3535             ret = ec_ioctl_master_state(master, arg, ctx);
       
  3536             break;
       
  3537         case EC_IOCTL_MASTER_LINK_STATE:
       
  3538             ret = ec_ioctl_master_link_state(master, arg, ctx);
       
  3539             break;
       
  3540         case EC_IOCTL_APP_TIME:
       
  3541             if (!ctx->writable) {
       
  3542                 ret = -EPERM;
       
  3543                 break;
       
  3544             }
       
  3545             ret = ec_ioctl_app_time(master, arg, ctx);
       
  3546             break;
       
  3547         case EC_IOCTL_SYNC_REF:
       
  3548             if (!ctx->writable) {
       
  3549                 ret = -EPERM;
       
  3550                 break;
       
  3551             }
       
  3552             ret = ec_ioctl_sync_ref(master, arg, ctx);
       
  3553             break;
       
  3554         case EC_IOCTL_SYNC_SLAVES:
       
  3555             if (!ctx->writable) {
       
  3556                 ret = -EPERM;
       
  3557                 break;
       
  3558             }
       
  3559             ret = ec_ioctl_sync_slaves(master, arg, ctx);
       
  3560             break;
       
  3561         case EC_IOCTL_SYNC_MON_QUEUE:
       
  3562             if (!ctx->writable) {
       
  3563                 ret = -EPERM;
       
  3564                 break;
       
  3565             }
       
  3566             ret = ec_ioctl_sync_mon_queue(master, arg, ctx);
       
  3567             break;
       
  3568         case EC_IOCTL_SYNC_MON_PROCESS:
       
  3569             if (!ctx->writable) {
       
  3570                 ret = -EPERM;
       
  3571                 break;
       
  3572             }
       
  3573             ret = ec_ioctl_sync_mon_process(master, arg, ctx);
       
  3574             break;
       
  3575         case EC_IOCTL_RESET:
       
  3576             if (!ctx->writable) {
       
  3577                 ret = -EPERM;
       
  3578                 break;
       
  3579             }
       
  3580             ret = ec_ioctl_reset(master, arg, ctx);
       
  3581             break;
       
  3582         case EC_IOCTL_SC_SYNC:
       
  3583             if (!ctx->writable) {
       
  3584                 ret = -EPERM;
       
  3585                 break;
       
  3586             }
       
  3587             ret = ec_ioctl_sc_sync(master, arg, ctx);
       
  3588             break;
       
  3589         case EC_IOCTL_SC_WATCHDOG:
       
  3590             if (!ctx->writable) {
       
  3591                 ret = -EPERM;
       
  3592                 break;
       
  3593             }
       
  3594             ret = ec_ioctl_sc_watchdog(master, arg, ctx);
       
  3595             break;
       
  3596         case EC_IOCTL_SC_ADD_PDO:
       
  3597             if (!ctx->writable) {
       
  3598                 ret = -EPERM;
       
  3599                 break;
       
  3600             }
       
  3601             ret = ec_ioctl_sc_add_pdo(master, arg, ctx);
       
  3602             break;
       
  3603         case EC_IOCTL_SC_CLEAR_PDOS:
       
  3604             if (!ctx->writable) {
       
  3605                 ret = -EPERM;
       
  3606                 break;
       
  3607             }
       
  3608             ret = ec_ioctl_sc_clear_pdos(master, arg, ctx);
       
  3609             break;
       
  3610         case EC_IOCTL_SC_ADD_ENTRY:
       
  3611             if (!ctx->writable) {
       
  3612                 ret = -EPERM;
       
  3613                 break;
       
  3614             }
       
  3615             ret = ec_ioctl_sc_add_entry(master, arg, ctx);
       
  3616             break;
       
  3617         case EC_IOCTL_SC_CLEAR_ENTRIES:
       
  3618             if (!ctx->writable) {
       
  3619                 ret = -EPERM;
       
  3620                 break;
       
  3621             }
       
  3622             ret = ec_ioctl_sc_clear_entries(master, arg, ctx);
       
  3623             break;
       
  3624         case EC_IOCTL_SC_REG_PDO_ENTRY:
       
  3625             if (!ctx->writable) {
       
  3626                 ret = -EPERM;
       
  3627                 break;
       
  3628             }
       
  3629             ret = ec_ioctl_sc_reg_pdo_entry(master, arg, ctx);
       
  3630             break;
       
  3631         case EC_IOCTL_SC_DC:
       
  3632             if (!ctx->writable) {
       
  3633                 ret = -EPERM;
       
  3634                 break;
       
  3635             }
       
  3636             ret = ec_ioctl_sc_dc(master, arg, ctx);
       
  3637             break;
       
  3638         case EC_IOCTL_SC_SDO:
       
  3639             if (!ctx->writable) {
       
  3640                 ret = -EPERM;
       
  3641                 break;
       
  3642             }
       
  3643             ret = ec_ioctl_sc_sdo(master, arg, ctx);
       
  3644             break;
       
  3645         case EC_IOCTL_SC_SDO_REQUEST:
       
  3646             if (!ctx->writable) {
       
  3647                 ret = -EPERM;
       
  3648                 break;
       
  3649             }
       
  3650             ret = ec_ioctl_sc_create_sdo_request(master, arg, ctx);
       
  3651             break;
       
  3652         case EC_IOCTL_SC_VOE:
       
  3653             if (!ctx->writable) {
       
  3654                 ret = -EPERM;
       
  3655                 break;
       
  3656             }
       
  3657             ret = ec_ioctl_sc_create_voe_handler(master, arg, ctx);
       
  3658             break;
       
  3659         case EC_IOCTL_SC_STATE:
       
  3660             ret = ec_ioctl_sc_state(master, arg, ctx);
       
  3661             break;
       
  3662         case EC_IOCTL_SC_IDN:
       
  3663             if (!ctx->writable) {
       
  3664                 ret = -EPERM;
       
  3665                 break;
       
  3666             }
       
  3667             ret = ec_ioctl_sc_idn(master, arg, ctx);
       
  3668             break;
       
  3669         case EC_IOCTL_DOMAIN_OFFSET:
       
  3670             ret = ec_ioctl_domain_offset(master, arg, ctx);
       
  3671             break;
       
  3672         case EC_IOCTL_DOMAIN_PROCESS:
       
  3673             if (!ctx->writable) {
       
  3674                 ret = -EPERM;
       
  3675                 break;
       
  3676             }
       
  3677             ret = ec_ioctl_domain_process(master, arg, ctx);
       
  3678             break;
       
  3679         case EC_IOCTL_DOMAIN_QUEUE:
       
  3680             if (!ctx->writable) {
       
  3681                 ret = -EPERM;
       
  3682                 break;
       
  3683             }
       
  3684             ret = ec_ioctl_domain_queue(master, arg, ctx);
       
  3685             break;
       
  3686         case EC_IOCTL_DOMAIN_STATE:
       
  3687             ret = ec_ioctl_domain_state(master, arg, ctx);
       
  3688             break;
       
  3689         case EC_IOCTL_SDO_REQUEST_TIMEOUT:
       
  3690             if (!ctx->writable) {
       
  3691                 ret = -EPERM;
       
  3692                 break;
       
  3693             }
       
  3694             ret = ec_ioctl_sdo_request_timeout(master, arg, ctx);
       
  3695             break;
       
  3696         case EC_IOCTL_SDO_REQUEST_STATE:
       
  3697             ret = ec_ioctl_sdo_request_state(master, arg, ctx);
       
  3698             break;
       
  3699         case EC_IOCTL_SDO_REQUEST_READ:
       
  3700             if (!ctx->writable) {
       
  3701                 ret = -EPERM;
       
  3702                 break;
       
  3703             }
       
  3704             ret = ec_ioctl_sdo_request_read(master, arg, ctx);
       
  3705             break;
       
  3706         case EC_IOCTL_SDO_REQUEST_WRITE:
       
  3707             if (!ctx->writable) {
       
  3708                 ret = -EPERM;
       
  3709                 break;
       
  3710             }
       
  3711             ret = ec_ioctl_sdo_request_write(master, arg, ctx);
       
  3712             break;
       
  3713         case EC_IOCTL_SDO_REQUEST_DATA:
       
  3714             ret = ec_ioctl_sdo_request_data(master, arg, ctx);
       
  3715             break;
       
  3716         case EC_IOCTL_VOE_SEND_HEADER:
       
  3717             if (!ctx->writable) {
       
  3718                 ret = -EPERM;
       
  3719                 break;
       
  3720             }
       
  3721             ret = ec_ioctl_voe_send_header(master, arg, ctx);
       
  3722             break;
       
  3723         case EC_IOCTL_VOE_REC_HEADER:
       
  3724             ret = ec_ioctl_voe_rec_header(master, arg, ctx);
       
  3725             break;
       
  3726         case EC_IOCTL_VOE_READ:
       
  3727             if (!ctx->writable) {
       
  3728                 ret = -EPERM;
       
  3729                 break;
       
  3730             }
       
  3731             ret = ec_ioctl_voe_read(master, arg, ctx);
       
  3732             break;
       
  3733         case EC_IOCTL_VOE_READ_NOSYNC:
       
  3734             if (!ctx->writable) {
       
  3735                 ret = -EPERM;
       
  3736                 break;
       
  3737             }
       
  3738             ret = ec_ioctl_voe_read_nosync(master, arg, ctx);
       
  3739             break;
       
  3740         case EC_IOCTL_VOE_WRITE:
       
  3741             if (!ctx->writable) {
       
  3742                 ret = -EPERM;
       
  3743                 break;
       
  3744             }
       
  3745             ret = ec_ioctl_voe_write(master, arg, ctx);
       
  3746             break;
       
  3747         case EC_IOCTL_VOE_EXEC:
       
  3748             if (!ctx->writable) {
       
  3749                 ret = -EPERM;
       
  3750                 break;
       
  3751             }
       
  3752             ret = ec_ioctl_voe_exec(master, arg, ctx);
       
  3753             break;
       
  3754         case EC_IOCTL_VOE_DATA:
       
  3755             ret = ec_ioctl_voe_data(master, arg, ctx);
       
  3756             break;
       
  3757         case EC_IOCTL_SET_SEND_INTERVAL:
       
  3758             if (!ctx->writable) {
       
  3759                 ret = -EPERM;
       
  3760                 break;
       
  3761             }
       
  3762             ret = ec_ioctl_set_send_interval(master, arg, ctx);
       
  3763             break;
       
  3764         default:
       
  3765             ret = -ENOTTY;
       
  3766             break;
       
  3767     }
       
  3768 
       
  3769 #if DEBUG_LATENCY
       
  3770     b = get_cycles();
       
  3771     t = (unsigned int) ((b - a) * 1000LL) / cpu_khz;
       
  3772     if (t > 50) {
       
  3773         EC_MASTER_WARN(master, "ioctl(0x%02x) took %u us.\n",
       
  3774                 _IOC_NR(cmd), t);
       
  3775     }
       
  3776 #endif
       
  3777 
       
  3778     return ret;
       
  3779 }
       
  3780 
       
  3781 /*****************************************************************************/