device.c

Go to the documentation of this file.
00001 /******************************************************************************
00002  *
00003  *  $Id: device.c 426 2006-05-29 09:08:56Z fp $
00004  *
00005  *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
00006  *
00007  *  This file is part of the IgH EtherCAT Master.
00008  *
00009  *  The IgH EtherCAT Master is free software; you can redistribute it
00010  *  and/or modify it under the terms of the GNU General Public License
00011  *  as published by the Free Software Foundation; either version 2 of the
00012  *  License, or (at your option) any later version.
00013  *
00014  *  The IgH EtherCAT Master is distributed in the hope that it will be
00015  *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *  GNU General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU General Public License
00020  *  along with the IgH EtherCAT Master; if not, write to the Free Software
00021  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  *  The right to use EtherCAT Technology is granted and comes free of
00024  *  charge under condition of compatibility of product made by
00025  *  Licensee. People intending to distribute/sell products based on the
00026  *  code, have to sign an agreement to guarantee that products using
00027  *  software based on IgH EtherCAT master stay compatible with the actual
00028  *  EtherCAT specification (which are released themselves as an open
00029  *  standard) as the (only) precondition to have the right to use EtherCAT
00030  *  Technology, IP and trade marks.
00031  *
00032  *****************************************************************************/
00033 
00039 /*****************************************************************************/
00040 
00041 #include <linux/module.h>
00042 #include <linux/skbuff.h>
00043 #include <linux/if_ether.h>
00044 #include <linux/netdevice.h>
00045 #include <linux/delay.h>
00046 
00047 #include "device.h"
00048 #include "master.h"
00049 
00050 /*****************************************************************************/
00051 
00057 int ec_device_init(ec_device_t *device, 
00058                    ec_master_t *master, 
00059                    struct net_device *net_dev, 
00060                    ec_isr_t isr, 
00061                    struct module *module 
00062                    )
00063 {
00064     struct ethhdr *eth;
00065 
00066     device->master = master;
00067     device->dev = net_dev;
00068     device->isr = isr;
00069     device->module = module;
00070 
00071     device->open = 0;
00072     device->link_state = 0; // down
00073 
00074     if (ec_debug_init(&device->dbg)) {
00075         EC_ERR("Failed to init debug device!\n");
00076         goto out_return;
00077     }
00078 
00079     if (!(device->tx_skb = dev_alloc_skb(ETH_FRAME_LEN))) {
00080         EC_ERR("Error allocating device socket buffer!\n");
00081         goto out_debug;
00082     }
00083 
00084     device->tx_skb->dev = net_dev;
00085 
00086     // add Ethernet-II-header
00087     skb_reserve(device->tx_skb, ETH_HLEN);
00088     eth = (struct ethhdr *) skb_push(device->tx_skb, ETH_HLEN);
00089     eth->h_proto = htons(0x88A4);
00090     memcpy(eth->h_source, net_dev->dev_addr, net_dev->addr_len);
00091     memset(eth->h_dest, 0xFF, net_dev->addr_len);
00092 
00093     return 0;
00094 
00095  out_debug:
00096     ec_debug_clear(&device->dbg);
00097  out_return:
00098     return -1;
00099 }
00100 
00101 /*****************************************************************************/
00102 
00107 void ec_device_clear(ec_device_t *device )
00108 {
00109     if (device->open) ec_device_close(device);
00110     if (device->tx_skb) dev_kfree_skb(device->tx_skb);
00111     ec_debug_clear(&device->dbg);
00112 }
00113 
00114 /*****************************************************************************/
00115 
00121 int ec_device_open(ec_device_t *device )
00122 {
00123     unsigned int i;
00124 
00125     if (!device->dev) {
00126         EC_ERR("No net_device to open!\n");
00127         return -1;
00128     }
00129 
00130     if (device->open) {
00131         EC_WARN("Device already opened!\n");
00132         return 0;
00133     }
00134 
00135     // device could have received frames before
00136     for (i = 0; i < 4; i++) ec_device_call_isr(device);
00137 
00138     device->link_state = 0;
00139 
00140     if (device->dev->open(device->dev) == 0) device->open = 1;
00141 
00142     return device->open ? 0 : -1;
00143 }
00144 
00145 /*****************************************************************************/
00146 
00152 int ec_device_close(ec_device_t *device )
00153 {
00154     if (!device->dev) {
00155         EC_ERR("No device to close!\n");
00156         return -1;
00157     }
00158 
00159     if (!device->open) {
00160         EC_WARN("Device already closed!\n");
00161         return 0;
00162     }
00163 
00164     if (device->dev->stop(device->dev) == 0) device->open = 0;
00165 
00166     return !device->open ? 0 : -1;
00167 }
00168 
00169 /*****************************************************************************/
00170 
00176 uint8_t *ec_device_tx_data(ec_device_t *device )
00177 {
00178     return device->tx_skb->data + ETH_HLEN;
00179 }
00180 
00181 /*****************************************************************************/
00182 
00189 void ec_device_send(ec_device_t *device, 
00190                     size_t size 
00191                     )
00192 {
00193     if (unlikely(!device->link_state)) // Link down
00194         return;
00195 
00196     // set the right length for the data
00197     device->tx_skb->len = ETH_HLEN + size;
00198 
00199     if (unlikely(device->master->debug_level > 1)) {
00200         EC_DBG("sending frame:\n");
00201         ec_print_data(device->tx_skb->data + ETH_HLEN, size);
00202     }
00203 
00204     ec_debug_send(&device->dbg, device->tx_skb->data, ETH_HLEN + size);
00205 
00206     // start sending
00207     device->dev->hard_start_xmit(device->tx_skb, device->dev);
00208 }
00209 
00210 /*****************************************************************************/
00211 
00219 void ec_device_call_isr(ec_device_t *device )
00220 {
00221     if (likely(device->isr)) device->isr(0, device->dev, NULL);
00222 }
00223 
00224 /******************************************************************************
00225  *  Device interface
00226  *****************************************************************************/
00227 
00235 void ecdev_receive(ec_device_t *device, 
00236                    const void *data, 
00237                    size_t size 
00238                    )
00239 {
00240     if (unlikely(device->master->debug_level > 1)) {
00241         EC_DBG("Received frame:\n");
00242         ec_print_data_diff(device->tx_skb->data + ETH_HLEN,
00243                            data + ETH_HLEN, size - ETH_HLEN);
00244     }
00245 
00246     ec_debug_send(&device->dbg, data, size);
00247 
00248     ec_master_receive(device->master, data + ETH_HLEN, size - ETH_HLEN);
00249 }
00250 
00251 /*****************************************************************************/
00252 
00260 void ecdev_link_state(ec_device_t *device, 
00261                       uint8_t state 
00262                       )
00263 {
00264     if (unlikely(!device)) {
00265         EC_WARN("ecdev_link_state: no device!\n");
00266         return;
00267     }
00268 
00269     if (likely(state != device->link_state)) {
00270         device->link_state = state;
00271         EC_INFO("Link state changed to %s.\n", (state ? "UP" : "DOWN"));
00272     }
00273 }
00274 
00275 /*****************************************************************************/
00276 
00279 EXPORT_SYMBOL(ecdev_receive);
00280 EXPORT_SYMBOL(ecdev_link_state);
00281 
00284 /*****************************************************************************/

Generated on Wed Aug 2 18:41:43 2006 for IgH EtherCAT master by  doxygen 1.4.6