fp@1335: /****************************************************************************** fp@1335: * fp@1335: * $Id$ fp@1335: * fp@1363: * Copyright (C) 2008 Olav Zarges, imc Messsysteme GmbH fp@1335: * fp@1335: * This file is part of the IgH EtherCAT Master. fp@1335: * fp@1363: * The IgH EtherCAT Master is free software; you can redistribute it and/or fp@1363: * modify it under the terms of the GNU General Public License version 2, as fp@1363: * published by the Free Software Foundation. fp@1335: * fp@1363: * The IgH EtherCAT Master is distributed in the hope that it will be useful, fp@1363: * but WITHOUT ANY WARRANTY; without even the implied warranty of fp@1363: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General fp@1363: * Public License for more details. fp@1335: * fp@1363: * You should have received a copy of the GNU General Public License along fp@1363: * with the IgH EtherCAT Master; if not, write to the Free Software fp@1335: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@1335: * fp@1363: * --- fp@1363: * fp@1363: * The license mentioned above concerns the source code only. Using the fp@1363: * EtherCAT technology and brand is only permitted in compliance with the fp@1363: * industrial property and similar rights of Beckhoff Automation GmbH. fp@1335: * fp@1335: *****************************************************************************/ fp@1335: fp@1335: /** \file fp@1335: * File-over-EtherCAT request functions. fp@1335: */ fp@1335: fp@1335: /*****************************************************************************/ fp@1335: fp@1335: #include fp@1335: #include fp@1975: #include fp@1335: fp@1335: #include "foe_request.h" fp@1336: #include "foe.h" fp@1335: fp@1335: /*****************************************************************************/ fp@1335: fp@1335: /** Default timeout in ms to wait for FoE transfer responses. fp@1335: */ fp@1335: #define EC_FOE_REQUEST_RESPONSE_TIMEOUT 3000 fp@1335: fp@1335: /*****************************************************************************/ fp@1335: fp@1335: void ec_foe_request_clear_data(ec_foe_request_t *); fp@1335: fp@1335: /*****************************************************************************/ fp@1335: fp@1335: /** FoE request constructor. fp@1335: */ fp@1335: void ec_foe_request_init( fp@1335: ec_foe_request_t *req, /**< FoE request. */ fp@1335: uint8_t* file_name /** filename */) fp@1335: { fp@2464: INIT_LIST_HEAD(&req->list); fp@1335: req->buffer = NULL; fp@1335: req->file_name = file_name; fp@1335: req->buffer_size = 0; fp@1335: req->data_size = 0; fp@1335: req->dir = EC_DIR_INVALID; fp@1335: req->issue_timeout = 0; // no timeout fp@1335: req->response_timeout = EC_FOE_REQUEST_RESPONSE_TIMEOUT; fp@1335: req->state = EC_INT_REQUEST_INIT; fp@1336: req->result = FOE_BUSY; fp@1336: req->error_code = 0x00000000; fp@1335: } fp@1335: fp@1335: /*****************************************************************************/ fp@1335: fp@1335: /** FoE request destructor. fp@1335: */ fp@1335: void ec_foe_request_clear( fp@1335: ec_foe_request_t *req /**< FoE request. */ fp@1335: ) fp@1335: { fp@1335: ec_foe_request_clear_data(req); fp@1335: } fp@1335: fp@1335: /*****************************************************************************/ fp@1335: fp@1335: /** FoE request destructor. fp@1335: */ fp@1335: void ec_foe_request_clear_data( fp@1335: ec_foe_request_t *req /**< FoE request. */ fp@1335: ) fp@1335: { fp@1335: if (req->buffer) { fp@1335: kfree(req->buffer); fp@1335: req->buffer = NULL; fp@1335: } fp@1335: fp@1335: req->buffer_size = 0; fp@1335: req->data_size = 0; fp@1335: } fp@1335: fp@1335: /*****************************************************************************/ fp@1335: fp@1335: /** Pre-allocates the data memory. fp@1335: * fp@2522: * If the internal \a buffer_size is already bigger than \a size, nothing is fp@2522: * done. fp@2522: * fp@2522: * \return Zero on success, otherwise a negative error code. fp@1335: */ fp@1335: int ec_foe_request_alloc( fp@1335: ec_foe_request_t *req, /**< FoE request. */ fp@1335: size_t size /**< Data size to allocate. */ fp@1335: ) fp@1335: { fp@2464: if (size <= req->buffer_size) { fp@1335: return 0; fp@2464: } fp@1335: fp@1335: ec_foe_request_clear_data(req); fp@1335: fp@1335: if (!(req->buffer = (uint8_t *) kmalloc(size, GFP_KERNEL))) { fp@1543: EC_ERR("Failed to allocate %zu bytes of FoE memory.\n", size); fp@2464: return -ENOMEM; fp@1335: } fp@1335: fp@1335: req->buffer_size = size; fp@1335: req->data_size = 0; fp@1335: return 0; fp@1335: } fp@1335: fp@1335: /*****************************************************************************/ fp@1335: fp@1335: /** Copies FoE data from an external source. fp@1335: * fp@1335: * If the \a buffer_size is to small, new memory is allocated. fp@2522: * fp@2522: * \return Zero on success, otherwise a negative error code. fp@1335: */ fp@1335: int ec_foe_request_copy_data( fp@1335: ec_foe_request_t *req, /**< FoE request. */ fp@1335: const uint8_t *source, /**< Source data. */ fp@1335: size_t size /**< Number of bytes in \a source. */ fp@1335: ) fp@1335: { fp@2464: int ret; fp@2464: fp@2464: ret = ec_foe_request_alloc(req, size); fp@2464: if (ret) { fp@2464: return ret; fp@2464: } fp@1335: fp@1335: memcpy(req->buffer, source, size); fp@1335: req->data_size = size; fp@1335: return 0; fp@1335: } fp@1335: fp@1335: /*****************************************************************************/ fp@1335: fp@1335: /** Checks, if the timeout was exceeded. fp@1335: * fp@1335: * \return non-zero if the timeout was exceeded, else zero. fp@1335: */ fp@1465: int ec_foe_request_timed_out( fp@1465: const ec_foe_request_t *req /**< FoE request. */ fp@1465: ) fp@1335: { fp@1335: return req->issue_timeout fp@1335: && jiffies - req->jiffies_start > HZ * req->issue_timeout / 1000; fp@1335: } fp@1335: fp@1335: /*****************************************************************************/ fp@1335: fp@1465: /** Set the request timeout. fp@1465: */ fp@1465: void ec_foe_request_timeout( fp@1465: ec_foe_request_t *req, /**< FoE request. */ fp@1465: uint32_t timeout /**< Timeout in ms. */ fp@1465: ) fp@1335: { fp@1335: req->issue_timeout = timeout; fp@1335: } fp@1335: fp@1335: /*****************************************************************************/ fp@1335: fp@1465: /** Returns a pointer to the request's data. fp@1465: * fp@1465: * \return Data pointer. fp@1465: */ fp@1465: uint8_t *ec_foe_request_data( fp@1465: ec_foe_request_t *req /**< FoE request. */ fp@1465: ) fp@1335: { fp@1335: return req->buffer; fp@1335: } fp@1335: fp@1335: /*****************************************************************************/ fp@1335: fp@1465: /** Returns the data size. fp@1465: * fp@1465: * \return Data size. fp@1465: */ fp@1465: size_t ec_foe_request_data_size( fp@1465: const ec_foe_request_t *req /**< FoE request. */ fp@1465: ) fp@1335: { fp@1335: return req->data_size; fp@1335: } fp@1335: fp@1335: /*****************************************************************************/ fp@1335: fp@1465: /** Prepares a read request (slave to master). fp@1465: */ fp@1465: void ec_foe_request_read( fp@1465: ec_foe_request_t *req /**< FoE request. */ fp@1465: ) fp@1335: { fp@1335: req->dir = EC_DIR_INPUT; fp@1335: req->state = EC_INT_REQUEST_QUEUED; fp@1336: req->result = FOE_BUSY; fp@1335: req->jiffies_start = jiffies; fp@1335: } fp@1335: fp@1335: /*****************************************************************************/ fp@1335: fp@1465: /** Prepares a write request (master to slave). fp@1465: */ fp@1465: void ec_foe_request_write( fp@1465: ec_foe_request_t *req /**< FoE request. */ fp@1465: ) fp@1335: { fp@1335: req->dir = EC_DIR_OUTPUT; fp@1335: req->state = EC_INT_REQUEST_QUEUED; fp@1336: req->result = FOE_BUSY; fp@1335: req->jiffies_start = jiffies; fp@1335: } fp@1335: fp@1335: /*****************************************************************************/