Made master devices persistent; added ec_device_attach() and ec_device_detach().
authorFlorian Pose <fp@igh-essen.com>
Tue, 20 Feb 2007 17:15:43 +0000
changeset 579 17c6fd3b076e
parent 578 f402b4bd2f4d
child 580 ba7e9b82ab3a
Made master devices persistent; added ec_device_attach() and ec_device_detach().
master/device.c
master/device.h
master/ethernet.c
master/master.c
master/master.h
master/module.c
--- a/master/device.c	Tue Feb 20 13:42:44 2007 +0000
+++ b/master/device.c	Tue Feb 20 17:15:43 2007 +0000
@@ -54,73 +54,97 @@
 */
 
 int ec_device_init(ec_device_t *device, /**< EtherCAT device */
-                   ec_master_t *master, /**< master owning the device */
-                   struct net_device *net_dev, /**< net_device structure */
-                   ec_pollfunc_t poll, /**< pointer to device's poll function */
-                   struct module *module /**< the device's module */
-                   )
-{
-    struct ethhdr *eth;
-
+        ec_master_t *master /**< master owning the device */
+        )
+{
     device->master = master;
+
+#ifdef EC_DBG_IF
+    if (ec_debug_init(&device->dbg)) {
+        EC_ERR("Failed to init debug device!\n");
+        goto out_return;
+    }
+#endif
+
+    if (!(device->tx_skb = dev_alloc_skb(ETH_FRAME_LEN))) {
+        EC_ERR("Error allocating device socket buffer!\n");
+#ifdef EC_DBG_IF
+        goto out_debug;
+#else
+        goto out_return;
+#endif
+    }
+
+    // add Ethernet-II-header
+    skb_reserve(device->tx_skb, ETH_HLEN);
+    device->eth = (struct ethhdr *) skb_push(device->tx_skb, ETH_HLEN);
+    device->eth->h_proto = htons(0x88A4);
+    memset(device->eth->h_dest, 0xFF, ETH_ALEN);
+
+    ec_device_detach(device); // resets remaining fields
+    return 0;
+
+#ifdef EC_DBG_IF
+ out_debug:
+    ec_debug_clear(&device->dbg);
+#endif
+ out_return:
+    return -1;
+}
+
+/*****************************************************************************/
+
+/**
+   EtherCAT device destuctor.
+*/
+
+void ec_device_clear(ec_device_t *device /**< EtherCAT device */)
+{
+    if (device->open) ec_device_close(device);
+    dev_kfree_skb(device->tx_skb);
+#ifdef EC_DBG_IF
+    ec_debug_clear(&device->dbg);
+#endif
+}
+
+/*****************************************************************************/
+
+/**
+   Associate with net_device.
+*/
+
+void ec_device_attach(ec_device_t *device, /**< EtherCAT device */
+        struct net_device *net_dev, /**< net_device structure */
+        ec_pollfunc_t poll, /**< pointer to device's poll function */
+        struct module *module /**< the device's module */
+        )
+{
+    ec_device_detach(device); // resets fields
+
     device->dev = net_dev;
     device->poll = poll;
     device->module = module;
 
+    device->tx_skb->dev = net_dev;
+    memcpy(device->eth->h_source, net_dev->dev_addr, ETH_ALEN);
+}
+
+/*****************************************************************************/
+
+/**
+   Disconnect from net_device.
+*/
+
+void ec_device_detach(ec_device_t *device /**< EtherCAT device */)
+{
+    device->dev = NULL;
+    device->poll = NULL;
+    device->module = NULL;
     device->open = 0;
     device->link_state = 0; // down
-
     device->tx_count = 0;
     device->rx_count = 0;
-
-#ifdef EC_DBG_IF
-    if (ec_debug_init(&device->dbg)) {
-        EC_ERR("Failed to init debug device!\n");
-        goto out_return;
-    }
-#endif
-
-    if (!(device->tx_skb = dev_alloc_skb(ETH_FRAME_LEN))) {
-        EC_ERR("Error allocating device socket buffer!\n");
-#ifdef EC_DBG_IF
-        goto out_debug;
-#else
-        goto out_return;
-#endif
-    }
-
-    device->tx_skb->dev = net_dev;
-
-    // add Ethernet-II-header
-    skb_reserve(device->tx_skb, ETH_HLEN);
-    eth = (struct ethhdr *) skb_push(device->tx_skb, ETH_HLEN);
-    eth->h_proto = htons(0x88A4);
-    memcpy(eth->h_source, net_dev->dev_addr, net_dev->addr_len);
-    memset(eth->h_dest, 0xFF, net_dev->addr_len);
-
-    return 0;
-
-#ifdef EC_DBG_IF
- out_debug:
-    ec_debug_clear(&device->dbg);
-#endif
- out_return:
-    return -1;
-}
-
-/*****************************************************************************/
-
-/**
-   EtherCAT device destuctor.
-*/
-
-void ec_device_clear(ec_device_t *device /**< EtherCAT device */)
-{
-    if (device->open) ec_device_close(device);
-    if (device->tx_skb) dev_kfree_skb(device->tx_skb);
-#ifdef EC_DBG_IF
-    ec_debug_clear(&device->dbg);
-#endif
+    device->tx_skb->dev = NULL;
 }
 
 /*****************************************************************************/
--- a/master/device.h	Tue Feb 20 13:42:44 2007 +0000
+++ b/master/device.h	Tue Feb 20 17:15:43 2007 +0000
@@ -63,13 +63,14 @@
 {
     ec_master_t *master; /**< EtherCAT master */
     struct net_device *dev; /**< pointer to the assigned net_device */
+    ec_pollfunc_t poll; /**< pointer to the device's poll function */
+    struct module *module; /**< pointer to the device's owning module */
     uint8_t open; /**< true, if the net_device has been opened */
+    uint8_t link_state; /**< device link state */
     struct sk_buff *tx_skb; /**< transmit socket buffer */
-    ec_pollfunc_t poll; /**< pointer to the device's poll function */
+    struct ethhdr *eth; /**< pointer to ethernet header in socket buffer */
     cycles_t cycles_poll; /**< cycles of last poll */
     unsigned long jiffies_poll; /**< jiffies of last poll */
-    struct module *module; /**< pointer to the device's owning module */
-    uint8_t link_state; /**< device link state */
     unsigned int tx_count; /**< number of frames sent */
     unsigned int rx_count; /**< number of frames received */
 #ifdef EC_DBG_IF
@@ -79,10 +80,13 @@
 
 /*****************************************************************************/
 
-int ec_device_init(ec_device_t *, ec_master_t *, struct net_device *,
-                   ec_pollfunc_t, struct module *);
+int ec_device_init(ec_device_t *, ec_master_t *);
 void ec_device_clear(ec_device_t *);
 
+void ec_device_attach(ec_device_t *, struct net_device *, ec_pollfunc_t,
+        struct module *);
+void ec_device_detach(ec_device_t *);
+
 int ec_device_open(ec_device_t *);
 int ec_device_close(ec_device_t *);
 
--- a/master/ethernet.c	Tue Feb 20 13:42:44 2007 +0000
+++ b/master/ethernet.c	Tue Feb 20 17:15:43 2007 +0000
@@ -317,7 +317,7 @@
 
 void ec_eoe_state_rx_start(ec_eoe_t *eoe /**< EoE handler */)
 {
-    if (!eoe->slave->online || !eoe->slave->master->device->link_state)
+    if (!eoe->slave->online || !eoe->slave->master->main_device.link_state)
         return;
 
     ec_slave_mbox_prepare_check(eoe->slave, &eoe->datagram);
@@ -518,7 +518,7 @@
     unsigned int wakeup = 0;
 #endif
 
-    if (!eoe->slave->online || !eoe->slave->master->device->link_state)
+    if (!eoe->slave->online || !eoe->slave->master->main_device.link_state)
         return;
 
     spin_lock_bh(&eoe->tx_queue_lock);
--- a/master/master.c	Tue Feb 20 13:42:44 2007 +0000
+++ b/master/master.c	Tue Feb 20 17:15:43 2007 +0000
@@ -114,9 +114,7 @@
     atomic_set(&master->available, 1);
     master->index = index;
 
-    master->device = NULL;
     master->main_device_id = main_id;
-    master->backup_device = NULL;
     master->backup_device_id = backup_id;
     init_MUTEX(&master->device_sem);
 
@@ -167,6 +165,13 @@
     master->sdo_timer.data = (unsigned long) master;
     init_completion(&master->sdo_complete);
 
+    // init devices
+    if (ec_device_init(&master->main_device, master))
+        goto out_return;
+
+    if (ec_device_init(&master->backup_device, master))
+        goto out_clear_main;
+
     // create EoE handlers
     for (i = 0; i < eoeif_count; i++) {
         if (!(eoe = (ec_eoe_t *) kmalloc(sizeof(ec_eoe_t), GFP_KERNEL))) {
@@ -216,6 +221,10 @@
         ec_eoe_clear(eoe);
         kfree(eoe);
     }
+    ec_device_clear(&master->backup_device);
+out_clear_main:
+    ec_device_clear(&master->main_device);
+out_return:
     return -1;
 }
 
@@ -267,6 +276,9 @@
         kfree(eoe);
     }
 
+    ec_device_clear(&master->backup_device);
+    ec_device_clear(&master->main_device);
+
     EC_INFO("Master %i freed.\n", master->index);
 
     kfree(master);
@@ -594,7 +606,7 @@
 
     do {
         // fetch pointer to transmit socket buffer
-        frame_data = ec_device_tx_data(master->device);
+        frame_data = ec_device_tx_data(&master->main_device);
         cur_data = frame_data + EC_FRAME_HEADER_SIZE;
         follows_word = NULL;
         more_datagrams_waiting = 0;
@@ -657,7 +669,7 @@
             EC_DBG("frame size: %i\n", cur_data - frame_data);
 
         // send frame
-        ec_device_send(master->device, cur_data - frame_data);
+        ec_device_send(&master->main_device, cur_data - frame_data);
         cycles_sent = get_cycles();
         jiffies_sent = jiffies;
 
@@ -764,8 +776,8 @@
 
         // dequeue the received datagram
         datagram->state = EC_DATAGRAM_RECEIVED;
-        datagram->cycles_received = master->device->cycles_poll;
-        datagram->jiffies_received = master->device->jiffies_poll;
+        datagram->cycles_received = master->main_device.cycles_poll;
+        datagram->jiffies_received = master->main_device.jiffies_poll;
         list_del_init(&datagram->queue);
     }
 }
@@ -862,7 +874,7 @@
     
     off += ec_device_id_print(dev_id, buffer + off);
     
-    if (device) {
+    if (device->dev) {
         off += sprintf(buffer + off, " (connected).\n");      
         off += sprintf(buffer + off, "    Frames sent:     %u\n",
                 device->tx_count);
@@ -921,10 +933,10 @@
     }
     
     off += sprintf(buffer + off, "  Main: ");
-    off += ec_master_device_info(master->device,
+    off += ec_master_device_info(&master->main_device,
             master->main_device_id, buffer + off);
     off += sprintf(buffer + off, "  Backup: ");
-    off += ec_master_device_info(master->backup_device,
+    off += ec_master_device_info(&master->backup_device,
             master->backup_device_id, buffer + off);
 
     up(&master->device_sem);
@@ -1465,7 +1477,7 @@
 {
     ec_datagram_t *datagram, *n;
 
-    if (unlikely(!master->device->link_state)) {
+    if (unlikely(!master->main_device.link_state)) {
         // link is down, no datagram can be sent
         list_for_each_entry_safe(datagram, n, &master->datagram_queue, queue) {
             datagram->state = EC_DATAGRAM_ERROR;
@@ -1473,7 +1485,7 @@
         }
 
         // query link state
-        ec_device_poll(master->device);
+        ec_device_poll(&master->main_device);
         return;
     }
 
@@ -1494,7 +1506,7 @@
     cycles_t cycles_timeout;
 
     // receive datagrams
-    ec_device_poll(master->device);
+    ec_device_poll(&master->main_device);
 
     cycles_timeout = (cycles_t) EC_IO_TIMEOUT /* us */ * (cpu_khz / 1000);
 
@@ -1502,7 +1514,7 @@
     list_for_each_entry_safe(datagram, next, &master->datagram_queue, queue) {
         if (datagram->state != EC_DATAGRAM_SENT) continue;
 
-        if (master->device->cycles_poll - datagram->cycles_sent
+        if (master->main_device.cycles_poll - datagram->cycles_sent
             > cycles_timeout) {
             list_del_init(&datagram->queue);
             datagram->state = EC_DATAGRAM_TIMED_OUT;
--- a/master/master.h	Tue Feb 20 13:42:44 2007 +0000
+++ b/master/master.h	Tue Feb 20 17:15:43 2007 +0000
@@ -99,9 +99,9 @@
 
     struct kobject kobj; /**< kobject */
 
-    ec_device_t *device; /**< EtherCAT device */
+    ec_device_t main_device; /**< EtherCAT device */
     const ec_device_id_t *main_device_id; /**< ID of main device */
-    ec_device_t *backup_device; /**< EtherCAT backup device */
+    ec_device_t backup_device; /**< EtherCAT backup device */
     const ec_device_id_t *backup_device_id; /**< ID of backup device */
     struct semaphore device_sem; /**< device semaphore */
 
--- a/master/module.c	Tue Feb 20 13:42:44 2007 +0000
+++ b/master/module.c	Tue Feb 20 17:15:43 2007 +0000
@@ -342,54 +342,35 @@
     char str[50]; // FIXME
 
     list_for_each_entry(master, &masters, list) {
-        if (down_interruptible(&master->device_sem)) {
-            EC_ERR("Interrupted while waiting for device semaphore!\n");
-            goto out_return;
-        }
-
         if (ec_device_id_check(master->main_device_id, net_dev,
                     driver_name, device_index)) {
-
             ec_device_id_print(master->main_device_id, str);
             EC_INFO("Accepting device %s for master %u.\n",
                     str, master->index);
 
-            if (master->device) {
-                EC_ERR("Master %u already has a device.\n", master->index);
-                goto out_up;
+            if (down_interruptible(&master->device_sem)) {
+                EC_ERR("Interrupted while waiting for device semaphore!\n");
+                return -1;
+            }
+
+            if (master->main_device.dev) {
+                EC_ERR("Master %u already has a device attached.\n",
+                        master->index);
+                up(&master->device_sem);
+                return -1;
             }
             
-            if (!(master->device = (ec_device_t *)
-                        kmalloc(sizeof(ec_device_t), GFP_KERNEL))) {
-                EC_ERR("Failed to allocate device!\n");
-                goto out_up;
-            }
-
-            if (ec_device_init(master->device, master,
-                        net_dev, poll, module)) {
-                EC_ERR("Failed to init device!\n");
-                goto out_free;
-            }
-
+            ec_device_attach(&master->main_device, net_dev, poll, module);
             up(&master->device_sem);
+            
             sprintf(net_dev->name, "ec%u", master->index);
-            *ecdev = master->device; // offer accepted
+            *ecdev = &master->main_device; // offer accepted
             return 0; // no error
         }
-
-        up(&master->device_sem);
     }
 
     *ecdev = NULL; // offer declined
     return 0; // no error
-
- out_free:
-    kfree(master->device);
-    master->device = NULL;
- out_up:
-    up(&master->device_sem);
- out_return:
-    return 1;
 }
 
 /*****************************************************************************/
@@ -413,11 +394,8 @@
     EC_INFO("Master %u releasing main device %s.\n", master->index, str);
     
     down(&master->device_sem);
-    master->device = NULL;
+    ec_device_detach(device);
     up(&master->device_sem);
-    
-    ec_device_clear(device);
-    kfree(device);
 }
 
 /*****************************************************************************/
@@ -503,13 +481,13 @@
         goto out_release;
     }
 
-    if (!master->device) {
+    if (master->mode != EC_MASTER_MODE_IDLE) {
         up(&master->device_sem);
-        EC_ERR("Master %i has no assigned device!\n", master_index);
+        EC_ERR("Master %i still waiting for devices!\n", master_index);
         goto out_release;
     }
 
-    if (!try_module_get(master->device->module)) {
+    if (!try_module_get(master->main_device.module)) {
         up(&master->device_sem);
         EC_ERR("Device module is unloading!\n");
         goto out_release;
@@ -517,7 +495,7 @@
 
     up(&master->device_sem);
 
-    if (!master->device->link_state) {
+    if (!master->main_device.link_state) {
         EC_ERR("Link is DOWN.\n");
         goto out_module_put;
     }
@@ -531,7 +509,7 @@
     return master;
 
  out_module_put:
-    module_put(master->device->module);
+    module_put(master->main_device.module);
  out_release:
     atomic_inc(&master->available);
  out_return:
@@ -556,7 +534,7 @@
 
     ec_master_leave_operation_mode(master);
 
-    module_put(master->device->module);
+    module_put(master->main_device.module);
     atomic_inc(&master->available);
 
     EC_INFO("Released master %i.\n", master->index);