master/rtdm.c
branchstable-1.5
changeset 2433 3bdd7a747fae
child 2522 ec403cf308eb
equal deleted inserted replaced
2432:f4313f5aba88 2433:3bdd7a747fae
       
     1 /*****************************************************************************
       
     2  *
       
     3  *  $Id$
       
     4  *
       
     5  *  Copyright (C) 2009-2010  Moehwald GmbH B. Benner
       
     6  *                     2011  IgH Andreas Stewering-Bone
       
     7  *                     2012  Florian Pose <fp@igh-essen.com>
       
     8  *
       
     9  *  This file is part of the IgH EtherCAT master.
       
    10  *
       
    11  *  The IgH EtherCAT master is free software; you can redistribute it and/or
       
    12  *  modify it under the terms of the GNU General Public License as published
       
    13  *  by the Free Software Foundation; version 2 of the License.
       
    14  *
       
    15  *  The IgH EtherCAT master is distributed in the hope that it will be useful,
       
    16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
       
    18  *  Public License for more details.
       
    19  *
       
    20  *  You should have received a copy of the GNU General Public License along
       
    21  *  with the IgH EtherCAT master. If not, see <http://www.gnu.org/licenses/>.
       
    22  *
       
    23  *  The license mentioned above concerns the source code only. Using the
       
    24  *  EtherCAT technology and brand is only permitted in compliance with the
       
    25  *  industrial property and similar rights of Beckhoff Automation GmbH.
       
    26  *
       
    27  ****************************************************************************/
       
    28 
       
    29 #include <linux/module.h>
       
    30 #include <linux/slab.h>
       
    31 #include <linux/mman.h>
       
    32 
       
    33 #include <rtdm/rtdm_driver.h>
       
    34 
       
    35 #include "master.h"
       
    36 #include "ioctl.h"
       
    37 #include "rtdm.h"
       
    38 
       
    39 /** Set to 1 to enable device operations debugging.
       
    40  */
       
    41 #define DEBUG 0
       
    42 
       
    43 /****************************************************************************/
       
    44 
       
    45 /** Context structure for an open RTDM file handle.
       
    46  */
       
    47 typedef struct {
       
    48     rtdm_user_info_t *user_info;
       
    49     ec_ioctl_context_t ioctl_ctx;
       
    50 } ec_rtdm_context_t;
       
    51 
       
    52 /****************************************************************************/
       
    53 
       
    54 int ec_rtdm_open(struct rtdm_dev_context *, rtdm_user_info_t *, int);
       
    55 int ec_rtdm_close(struct rtdm_dev_context *, rtdm_user_info_t *);
       
    56 int ec_rtdm_ioctl(struct rtdm_dev_context *, rtdm_user_info_t *,
       
    57         unsigned int, void __user *);
       
    58 
       
    59 /****************************************************************************/
       
    60 
       
    61 int ec_rtdm_dev_init(
       
    62         ec_rtdm_dev_t *rtdm_dev,
       
    63         ec_master_t *master
       
    64         )
       
    65 {
       
    66     int ret;
       
    67 
       
    68     rtdm_dev->master = master;
       
    69 
       
    70     rtdm_dev->dev = kzalloc(sizeof(struct rtdm_device), GFP_KERNEL);
       
    71     if (!rtdm_dev->dev) {
       
    72         EC_MASTER_ERR(master, "Failed to reserve memory for RTDM device.\n");
       
    73         return -ENOMEM;
       
    74     }
       
    75 
       
    76     rtdm_dev->dev->struct_version = RTDM_DEVICE_STRUCT_VER;
       
    77     rtdm_dev->dev->device_flags = RTDM_NAMED_DEVICE;
       
    78     rtdm_dev->dev->context_size = sizeof(ec_rtdm_context_t);
       
    79     snprintf(rtdm_dev->dev->device_name, RTDM_MAX_DEVNAME_LEN,
       
    80             "EtherCAT%u", master->index);
       
    81     rtdm_dev->dev->open_nrt = ec_rtdm_open;
       
    82     rtdm_dev->dev->ops.close_nrt = ec_rtdm_close;
       
    83     rtdm_dev->dev->ops.ioctl_rt = ec_rtdm_ioctl;
       
    84     rtdm_dev->dev->ops.ioctl_nrt = ec_rtdm_ioctl;
       
    85     rtdm_dev->dev->device_class = RTDM_CLASS_EXPERIMENTAL;
       
    86     rtdm_dev->dev->device_sub_class = 222;
       
    87     rtdm_dev->dev->driver_name = "EtherCAT";
       
    88     rtdm_dev->dev->driver_version = RTDM_DRIVER_VER(1, 0, 2);
       
    89     rtdm_dev->dev->peripheral_name = rtdm_dev->dev->device_name;
       
    90     rtdm_dev->dev->provider_name = "EtherLab Community";
       
    91     rtdm_dev->dev->proc_name = rtdm_dev->dev->device_name;
       
    92     rtdm_dev->dev->device_data = rtdm_dev; /* pointer to parent */
       
    93 
       
    94     EC_MASTER_INFO(master, "Registering RTDM device %s.\n",
       
    95             rtdm_dev->dev->driver_name);
       
    96     ret = rtdm_dev_register(rtdm_dev->dev);
       
    97     if (ret) {
       
    98         EC_MASTER_ERR(master, "Initialization of RTDM interface failed"
       
    99                 " (return value %i).\n", ret);
       
   100         kfree(rtdm_dev->dev);
       
   101     }
       
   102 
       
   103     return ret;
       
   104 }
       
   105 
       
   106 /****************************************************************************/
       
   107 
       
   108 void ec_rtdm_dev_clear(
       
   109         ec_rtdm_dev_t *rtdm_dev
       
   110         )
       
   111 {
       
   112     int ret;
       
   113 
       
   114     EC_MASTER_INFO(rtdm_dev->master, "Unregistering RTDM device %s.\n",
       
   115             rtdm_dev->dev->driver_name);
       
   116     ret = rtdm_dev_unregister(rtdm_dev->dev, 1000 /* poll delay [ms] */);
       
   117     if (ret < 0) {
       
   118         EC_MASTER_WARN(rtdm_dev->master,
       
   119                 "Failed to unregister RTDM device (code %i).\n", ret);
       
   120     }
       
   121 
       
   122     kfree(rtdm_dev->dev);
       
   123 }
       
   124 
       
   125 /****************************************************************************/
       
   126 
       
   127 /** Driver open.
       
   128  */
       
   129 int ec_rtdm_open(
       
   130         struct rtdm_dev_context *context,
       
   131         rtdm_user_info_t *user_info,
       
   132         int oflags
       
   133         )
       
   134 {
       
   135     ec_rtdm_context_t *ctx = (ec_rtdm_context_t *) context->dev_private;
       
   136 #if DEBUG
       
   137     ec_rtdm_dev_t *rtdm_dev = (ec_rtdm_dev_t *) context->device->device_data;
       
   138 #endif
       
   139 
       
   140     ctx->user_info = user_info;
       
   141     ctx->ioctl_ctx.writable = oflags & O_WRONLY || oflags & O_RDWR;
       
   142     ctx->ioctl_ctx.requested = 0;
       
   143     ctx->ioctl_ctx.process_data = NULL;
       
   144     ctx->ioctl_ctx.process_data_size = 0;
       
   145 
       
   146 #if DEBUG
       
   147     EC_MASTER_INFO(rtdm_dev->master, "RTDM device %s opened.\n",
       
   148             context->device->device_name);
       
   149 #endif
       
   150     return 0;
       
   151 }
       
   152 
       
   153 /****************************************************************************/
       
   154 
       
   155 /** Driver close.
       
   156  */
       
   157 int ec_rtdm_close(struct rtdm_dev_context *context,
       
   158         rtdm_user_info_t *user_info)
       
   159 {
       
   160     ec_rtdm_context_t *ctx = (ec_rtdm_context_t *) context->dev_private;
       
   161     ec_rtdm_dev_t *rtdm_dev = (ec_rtdm_dev_t *) context->device->device_data;
       
   162 
       
   163     if (ctx->ioctl_ctx.requested) {
       
   164         ecrt_release_master(rtdm_dev->master);
       
   165 	}
       
   166 
       
   167 #if DEBUG
       
   168     EC_MASTER_INFO(rtdm_dev->master, "RTDM device %s closed.\n",
       
   169             context->device->device_name);
       
   170 #endif
       
   171     return 0;
       
   172 }
       
   173 
       
   174 /****************************************************************************/
       
   175 
       
   176 /** Driver ioctl.
       
   177  */
       
   178 int ec_rtdm_ioctl(
       
   179         struct rtdm_dev_context *context, /**< Context. */
       
   180         rtdm_user_info_t *user_info, /**< User data. */
       
   181         unsigned int request, /**< Request. */
       
   182         void __user *arg /**< Argument. */
       
   183         )
       
   184 {
       
   185     ec_rtdm_context_t *ctx = (ec_rtdm_context_t *) context->dev_private;
       
   186     ec_rtdm_dev_t *rtdm_dev = (ec_rtdm_dev_t *) context->device->device_data;
       
   187 
       
   188 #if DEBUG
       
   189     EC_MASTER_INFO(rtdm_dev->master, "ioctl(request = %u, ctl = %02x)"
       
   190             " on RTDM device %s.\n", request, _IOC_NR(request),
       
   191             context->device->device_name);
       
   192 #endif
       
   193     return ec_ioctl_rtdm(rtdm_dev->master, &ctx->ioctl_ctx, request, arg);
       
   194 }
       
   195 
       
   196 /****************************************************************************/
       
   197 
       
   198 /** Memory-map process data to user space.
       
   199  */
       
   200 int ec_rtdm_mmap(ec_ioctl_context_t *ioctl_ctx, void **user_address)
       
   201 {
       
   202     ec_rtdm_context_t *ctx =
       
   203         container_of(ioctl_ctx, ec_rtdm_context_t, ioctl_ctx);
       
   204     int ret;
       
   205 
       
   206     ret = rtdm_mmap_to_user(ctx->user_info,
       
   207             ioctl_ctx->process_data, ioctl_ctx->process_data_size,
       
   208             PROT_READ | PROT_WRITE,
       
   209             user_address,
       
   210             NULL, NULL);
       
   211     if (ret < 0) {
       
   212         return ret;
       
   213     }
       
   214 
       
   215     return 0;
       
   216 }
       
   217 
       
   218 /****************************************************************************/