# HG changeset patch # User Florian Pose # Date 1151334246 0 # Node ID 4bbe090553f761ccb55ef33935e5e94f31a6611c # Parent 9d7453c16adedfe26ae628b6ddb753bf738eb9d8 MERGE trunk -r428:447 -> branches/stable-1.0 (Complete EEPROM data, unloading buxfix, variable data, bridging) diff -r 9d7453c16ade -r 4bbe090553f7 FEATURES --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FEATURES Mon Jun 26 15:04:06 2006 +0000 @@ -0,0 +1,66 @@ +------------------------------------------------------------------------------- + +This is the FEATURES file of the IgH EtherCAT Master. + +$Id$ + +------------------------------------------------------------------------------- + +General Features: + +* Runs as kernel module for Linux 2.6. + +* Comes with EtherCAT-capable network driver for RTL8139 and compatible + network interface cards. + - Interrupt-less network driver operation. + - Easy implementation of additional network drivers through common device + interface of the master. + - Runs even with PCMCIA cards. + +* Supports multiple EtherCAT masters on one machine. + +* Supports any realtime extension through independent architecture. + - RTAI, IPIPE, ADEOS, etc. + - Runs well even without realtime extensions. + +* Common kernel interface, for realtime modules using EtherCAT functionality. + - Synchronous and asynchronous sending and receiving of frames. + - Avoidance of unnecessary copy operations for process data. + +* Separating slave groups through domains. + - Handling of multiple slave groups with different sampling rates. + - Automatic calculation of process data mapping, FMMU- and sync manager + configuration within the domains. + +* Master finite state machine (FSM). Thus: + - Bus monitoring during realtime operation. + - Automatic reconfiguration of slaves on bus power failure during realtime + operation. + - Controlling of slave states during realtime operation. + +* Free-Run mode, if master is idle. + - Automatic scanning of slaves upon topology changes. + - Bus visualisation and EoE processing without realtime process connected. + +* Implements the CANopen-over-EtherCAT (CoE) protocol. + - Configuration of CoE-capable slaves via SDO interface. + - SDO dictionary listing. + +* Implements the Ethernet-over-EtherCAT (EoE) protocol. + - Creates virtual network devices that are automatically coupled to + EoE-capable slaves. + - Thus natively supports either a switched or a routed EoE network + architecture. + +* User space interface via the System Filesystem (SysFS). + - User space tool for bus visualisation. + - Slave E²PROM image reading and writing. + +* Seamless integration in your favourite Linux distibution. + - Master and network device configuration via sysconfig files. + - UnitedLinux compatible init script for master control. + +* Virtual read-only network interface for debugging purposes and for + "sniffing" the EtherCAT traffic (through Ethereal, or others). + +------------------------------------------------------------------------------- diff -r 9d7453c16ade -r 4bbe090553f7 Makefile --- a/Makefile Mon May 29 09:54:18 2006 +0000 +++ b/Makefile Mon Jun 26 15:04:06 2006 +0000 @@ -1,6 +1,8 @@ #------------------------------------------------------------------------------ # -# EtherCAT Makefile +# Makefile +# +# IgH EtherCAT master # # $Id$ # @@ -53,9 +55,17 @@ KERNEL_DIR := /lib/modules/$(KERNEL)/build CURRENT_DIR := $(shell pwd) +INSTALL_MOD_DIR := ethercat modules: - $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) + $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) modules + +install: modules_install + @script/install.sh $(KERNEL) + +modules_install: + $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) \ + INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) modules_install clean: cleandoc $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean @@ -66,9 +76,6 @@ cleandoc: @rm -rf doc -install: - @script/install.sh $(KERNEL) - #------------------------------------------------------------------------------ endif diff -r 9d7453c16ade -r 4bbe090553f7 README --- a/README Mon May 29 09:54:18 2006 +0000 +++ b/README Mon Jun 26 15:04:06 2006 +0000 @@ -18,7 +18,7 @@ This is an Open-Source EtherCAT master implementation for Linux 2.6. -For more information, see +See the FEATURES file for a list of features. For more information, see http://etherlab.org diff -r 9d7453c16ade -r 4bbe090553f7 TODO --- a/TODO Mon May 29 09:54:18 2006 +0000 +++ b/TODO Mon Jun 26 15:04:06 2006 +0000 @@ -1,21 +1,39 @@ +------------------------------------------------------------------------------- EtherCAT master TODO -==================== $Id$ -- Mailbox-Handler -- Dispatching of received mailbox data? -- File access over EtherCAT (FoE) +------------------------------------------------------------------------------- -- Number of frames the NIC can handle -- Remove slave type information from master / read XML files from user space +Important things to do: -- eepro100 driver -- VLAN tagging +* New SDO-Configuration interface -- Calculate bus topology +* Remove slave type information from master / New RT Interface -- Documentation +* Always use state machines / remove simple IO code -- User space tool for configuration and visualisation +* SysFS interface + - Add secondary slave address + - Add SDO dictionary + +* Implement all EtherCAT commands + +* Determine number of frames the NIC can handle + +* Implement eepro100 driver + +------------------------------------------------------------------------------- + +Not-so-important things to do: + +* User space tool for configuration + +* Calculate bus topology + +* File access over EtherCAT (FoE) + +* Allow VLAN tagging + +------------------------------------------------------------------------------- diff -r 9d7453c16ade -r 4bbe090553f7 devices/8139too.c --- a/devices/8139too.c Mon May 29 09:54:18 2006 +0000 +++ b/devices/8139too.c Mon Jun 26 15:04:06 2006 +0000 @@ -133,6 +133,7 @@ #define DRV_NAME "ec_8139too" #define DRV_VERSION "0.9.27" + #include #include #include @@ -342,6 +343,7 @@ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ +/* prevent driver from being loaded automatically */ //MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl); /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ @@ -669,10 +671,8 @@ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ -MODULE_AUTHOR("Wilhelm Hagemeister ," - " Florian Pose "); -MODULE_DESCRIPTION("RealTek RTL-8139 Fast Ethernet" - " driver with EtherCAT functionality"); +MODULE_AUTHOR("Florian Pose "); +MODULE_DESCRIPTION("RealTek RTL-8139 EtherCAT driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(COMPILE_INFO); @@ -1050,8 +1050,8 @@ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ if (board_idx == ec_device_index) { - rtl_ec_net_dev = dev; - strcpy(dev->name, "ec0"); + rtl_ec_net_dev = dev; + strcpy(dev->name, "ec0"); } /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ @@ -1098,7 +1098,6 @@ (debug < 0 ? RTL8139_DEF_MSG_ENABLE : ((1 << debug) - 1)); spin_lock_init (&tp->lock); spin_lock_init (&tp->rx_lock); - init_waitqueue_head (&tp->thr_wait); init_completion (&tp->thr_exited); tp->mii.dev = dev; @@ -1111,11 +1110,10 @@ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - if (dev != rtl_ec_net_dev) { - DPRINTK("About to register device named %s (%p)...\n", - dev->name, dev); - i = register_netdev (dev); - if (i) goto err_out; + if (dev != rtl_ec_net_dev) { + DPRINTK("about to register device named %s (%p)...\n", dev->name, dev); + i = register_netdev (dev); + if (i) goto err_out; } /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ @@ -1207,10 +1205,10 @@ assert (dev != NULL); - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - - if (dev != rtl_ec_net_dev) { - unregister_netdev (dev); + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + + if (dev != rtl_ec_net_dev) { + unregister_netdev (dev); } /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ @@ -1417,16 +1415,12 @@ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ -#ifdef EC_DEBUG - printk(KERN_DEBUG "%s: open\n", dev->name); -#endif - - if (dev != rtl_ec_net_dev) { - retval = request_irq(dev->irq, rtl8139_interrupt, - SA_SHIRQ, dev->name, dev); - if (retval) - return retval; - } + if (dev != rtl_ec_net_dev) { + retval = request_irq(dev->irq, rtl8139_interrupt, + SA_SHIRQ, dev->name, dev); + if (retval) + return retval; + } /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ @@ -1434,24 +1428,24 @@ &tp->tx_bufs_dma); tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN, &tp->rx_ring_dma); - if (tp->tx_bufs == NULL || tp->rx_ring == NULL) - { - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - - if (dev != rtl_ec_net_dev) { - free_irq(dev->irq, dev); - } - - /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ - - if (tp->tx_bufs) - pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN, - tp->tx_bufs, tp->tx_bufs_dma); - if (tp->rx_ring) - pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN, - tp->rx_ring, tp->rx_ring_dma); - - return -ENOMEM; + if (tp->tx_bufs == NULL || tp->rx_ring == NULL) { + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + + if (dev != rtl_ec_net_dev) { + free_irq(dev->irq, dev); + } + + /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + + if (tp->tx_bufs) + pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN, + tp->tx_bufs, tp->tx_bufs_dma); + if (tp->rx_ring) + pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN, + tp->rx_ring, tp->rx_ring_dma); + + return -ENOMEM; + } tp->mii.full_duplex = tp->mii.force_media; @@ -1460,40 +1454,45 @@ rtl8139_init_ring (dev); rtl8139_hw_start (dev); - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - - if (dev != rtl_ec_net_dev) { - netif_start_queue (dev); - - if (netif_msg_ifup(tp)) { - printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#lx IRQ %d" - " GP Pins %2.2x %s-duplex.\n", - dev->name, pci_resource_start (tp->pci_dev, 1), - dev->irq, RTL_R8 (MediaStatus), - tp->mii.full_duplex ? "full" : "half"); - } - - rtl8139_start_thread(dev); + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + + if (dev != rtl_ec_net_dev) { + netif_start_queue (dev); + + if (netif_msg_ifup(tp)) + printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#lx IRQ %d" + " GP Pins %2.2x %s-duplex.\n", + dev->name, pci_resource_start (tp->pci_dev, 1), + dev->irq, RTL_R8 (MediaStatus), + tp->mii.full_duplex ? "full" : "half"); + + rtl8139_start_thread(dev); + } + + /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + + return 0; +} + + +static void rtl_check_media (struct net_device *dev, unsigned int init_media) +{ + struct rtl8139_private *tp = netdev_priv(dev); + + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + + if (dev != rtl_ec_net_dev) { + if (tp->phys[0] >= 0) { + mii_check_media(&tp->mii, netif_msg_link(tp), init_media); } + } else { + void __iomem *ioaddr = tp->mmio_addr; + uint16_t state = RTL_R16(BasicModeStatus) & BMSR_LSTATUS; + ecdev_link_state(rtl_ec_dev, state ? 1 : 0); + } /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ - return 0; -} - - -static void rtl_check_media (struct net_device *dev, unsigned int init_media) -{ - struct rtl8139_private *tp = netdev_priv(dev); - - if (dev == rtl_ec_net_dev) { - void __iomem *ioaddr = tp->mmio_addr; - uint16_t state = RTL_R16(BasicModeStatus) & BMSR_LSTATUS; - ecdev_link_state(rtl_ec_dev, state ? 1 : 0); - } - else if (tp->phys[0] >= 0) { - mii_check_media(&tp->mii, netif_msg_link(tp), init_media); - } } /* Start the hardware at open or resume. */ @@ -1560,9 +1559,9 @@ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - if (dev != rtl_ec_net_dev) { - /* Enable all known interrupts by setting the interrupt mask. */ - RTL_W16 (IntrMask, rtl8139_intr_mask); + if (dev != rtl_ec_net_dev) { + /* Enable all known interrupts by setting the interrupt mask. */ + RTL_W16 (IntrMask, rtl8139_intr_mask); } /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ @@ -1818,7 +1817,6 @@ " (queue head)" : ""); tp->xstats.tx_timeouts++; - printk(KERN_DEBUG "%s: tx_timeout\n", dev->name); /* disable Tx ASAP, if not already */ tmp8 = RTL_R8 (ChipCmd); @@ -1827,35 +1825,31 @@ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - - if (dev != rtl_ec_net_dev) { - spin_lock(&tp->rx_lock); - - /* Disable interrupts by clearing the interrupt mask. */ - RTL_W16 (IntrMask, 0x0000); - - /* Stop a shared interrupt from scavenging while we are. */ - spin_lock_irqsave (&tp->lock, flags); - rtl8139_tx_clear (tp); - spin_unlock_irqrestore (&tp->lock, flags); - - /* ...and finally, reset everything */ - - if (netif_running(dev)) { - rtl8139_hw_start (dev); - netif_wake_queue (dev); - } - - spin_unlock(&tp->rx_lock); + if (dev != rtl_ec_net_dev) { + spin_lock(&tp->rx_lock); + /* Disable interrupts by clearing the interrupt mask. */ + RTL_W16 (IntrMask, 0x0000); + + /* Stop a shared interrupt from scavenging while we are. */ + spin_lock_irqsave (&tp->lock, flags); + rtl8139_tx_clear (tp); + spin_unlock_irqrestore (&tp->lock, flags); + + /* ...and finally, reset everything */ + if (netif_running(dev)) { + rtl8139_hw_start (dev); + netif_wake_queue (dev); } - else { - rtl8139_tx_clear (tp); - rtl8139_hw_start(dev); - } + spin_unlock(&tp->rx_lock); + } else { + rtl8139_tx_clear (tp); + rtl8139_hw_start(dev); + } /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ } + static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) { struct rtl8139_private *tp = netdev_priv(dev); @@ -1866,27 +1860,27 @@ /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - - /* Note: the chip doesn't have auto-pad! */ - if (likely(len < TX_BUF_SIZE)) - { - if (len < ETH_ZLEN) - memset(tp->tx_buf[entry], 0, ETH_ZLEN); - - skb_copy_and_csum_dev(skb, tp->tx_buf[entry]); - if (dev != rtl_ec_net_dev) dev_kfree_skb(skb); - } - else - { - if (dev != rtl_ec_net_dev) dev_kfree_skb(skb); - tp->stats.tx_dropped++; - return 0; + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + + /* Note: the chip doesn't have auto-pad! */ + if (likely(len < TX_BUF_SIZE)) { + if (len < ETH_ZLEN) + memset(tp->tx_buf[entry], 0, ETH_ZLEN); + skb_copy_and_csum_dev(skb, tp->tx_buf[entry]); + if (dev != rtl_ec_net_dev) { + dev_kfree_skb(skb); + } + } else { + if (dev != rtl_ec_net_dev) { + dev_kfree_skb(skb); + } + tp->stats.tx_dropped++; + return 0; } if (dev != rtl_ec_net_dev) { - spin_lock_irq(&tp->lock); - } + spin_lock_irq(&tp->lock); + } /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ @@ -1901,15 +1895,14 @@ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ if (dev != rtl_ec_net_dev) { - if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) - netif_stop_queue (dev); - - spin_unlock_irq(&tp->lock); - - if (netif_msg_tx_queued(tp)) - printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n", - dev->name, len, entry); - } + if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) + netif_stop_queue (dev); + spin_unlock_irq(&tp->lock); + + if (netif_msg_tx_queued(tp)) + printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n", + dev->name, len, entry); + } /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ @@ -1928,7 +1921,6 @@ dirty_tx = tp->dirty_tx; tx_left = tp->cur_tx - dirty_tx; - while (tx_left > 0) { int entry = dirty_tx % NUM_TX_DESC; int txstatus; @@ -1971,7 +1963,7 @@ tx_left--; } - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ #ifndef RTL8139_NDEBUG if (dev != rtl_ec_net_dev && tp->cur_tx - dirty_tx > NUM_TX_DESC) { @@ -1981,20 +1973,20 @@ } #endif /* RTL8139_NDEBUG */ - /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ /* only wake the queue if we did work, and the queue is stopped */ if (tp->dirty_tx != dirty_tx) { tp->dirty_tx = dirty_tx; mb(); - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ if (dev != rtl_ec_net_dev) { - netif_wake_queue (dev); - } - - /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + netif_wake_queue (dev); + } + + /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ } } @@ -2128,9 +2120,15 @@ RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); + + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + while ((dev == rtl_ec_net_dev || netif_running(dev)) && received < budget && (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { + + /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + u32 ring_offset = cur_rx % RX_BUF_LEN; u32 rx_status; unsigned int pkt_size; @@ -2143,14 +2141,16 @@ rx_size = rx_status >> 16; pkt_size = rx_size - 4; - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - - if (dev != rtl_ec_net_dev && netif_msg_rx_status(tp)) - printk(KERN_DEBUG "%s: rtl8139_rx() status %4.4x, size %4.4x," - " cur %4.4x.\n", dev->name, rx_status, - rx_size, cur_rx); - - /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + + if (dev != rtl_ec_net_dev) { + if (netif_msg_rx_status(tp)) + printk(KERN_DEBUG "%s: rtl8139_rx() status %4.4x, size %4.4x," + " cur %4.4x.\n", dev->name, rx_status, + rx_size, cur_rx); + } + + /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ #if RTL8139_DEBUG > 2 { @@ -2199,48 +2199,46 @@ goto out; } - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - - if (dev != rtl_ec_net_dev) { - /* Malloc up new buffer, compatible with net-2e. */ - /* Omit the four octet CRC from the length. */ - skb = dev_alloc_skb(pkt_size + 2); - - if (likely(skb)) { - skb->dev = dev; - skb_reserve (skb, 2); /* 16 byte align the IP fields. */ + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + + if (dev != rtl_ec_net_dev) { + /* Malloc up new buffer, compatible with net-2e. */ + /* Omit the four octet CRC from the length. */ + + skb = dev_alloc_skb (pkt_size + 2); + if (likely(skb)) { + skb->dev = dev; + skb_reserve (skb, 2); /* 16 byte align the IP fields. */ #if RX_BUF_IDX == 3 - wrap_copy(skb, rx_ring, ring_offset+4, pkt_size); + wrap_copy(skb, rx_ring, ring_offset+4, pkt_size); #else - eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0); + eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0); #endif - skb_put (skb, pkt_size); - - skb->protocol = eth_type_trans (skb, dev); - - dev->last_rx = jiffies; - tp->stats.rx_bytes += pkt_size; - tp->stats.rx_packets++; - - netif_receive_skb (skb); - } else { - if (net_ratelimit()) - printk (KERN_WARNING - "%s: Memory squeeze, dropping packet.\n", - dev->name); - tp->stats.rx_dropped++; - } - } - else - { - ecdev_receive(rtl_ec_dev, - &rx_ring[ring_offset + 4], pkt_size); - dev->last_rx = jiffies; - tp->stats.rx_bytes += pkt_size; - tp->stats.rx_packets++; - } - - /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + skb_put (skb, pkt_size); + + skb->protocol = eth_type_trans (skb, dev); + + dev->last_rx = jiffies; + tp->stats.rx_bytes += pkt_size; + tp->stats.rx_packets++; + + netif_receive_skb (skb); + } else { + if (net_ratelimit()) + printk (KERN_WARNING + "%s: Memory squeeze, dropping packet.\n", + dev->name); + tp->stats.rx_dropped++; + } + } else { + ecdev_receive(rtl_ec_dev, + &rx_ring[ring_offset + 4], pkt_size); + dev->last_rx = jiffies; + tp->stats.rx_bytes += pkt_size; + tp->stats.rx_packets++; + } + + /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ received++; @@ -2337,11 +2335,10 @@ * Order is important since data can get interrupted * again when we think we are done. */ - - local_irq_disable(); - RTL_W16_F(IntrMask, rtl8139_intr_mask); - __netif_rx_complete(dev); - local_irq_enable(); + local_irq_disable(); + RTL_W16_F(IntrMask, rtl8139_intr_mask); + __netif_rx_complete(dev); + local_irq_enable(); } spin_unlock(&tp->rx_lock); @@ -2360,21 +2357,20 @@ int link_changed = 0; /* avoid bogus "uninit" warning */ int handled = 0; - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - - if (dev == rtl_ec_net_dev) { - status = RTL_R16 (IntrStatus); - } - else { - spin_lock(&tp->lock); - - status = RTL_R16 (IntrStatus); - - if (unlikely((status & rtl8139_intr_mask) == 0)) - goto out; - } - - /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + + if (dev != rtl_ec_net_dev) { + spin_lock (&tp->lock); + status = RTL_R16 (IntrStatus); + + /* shared irq? */ + if (unlikely((status & rtl8139_intr_mask) == 0)) + goto out; + } else { + status = RTL_R16 (IntrStatus); + } + + /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ handled = 1; @@ -2382,17 +2378,17 @@ if (unlikely(status == 0xFFFF)) goto out; - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ if (dev != rtl_ec_net_dev) { - /* close possible race's with dev_close */ - if (unlikely(!netif_running(dev))) { - RTL_W16 (IntrMask, 0); - goto out; - } - } - - /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + /* close possible race's with dev_close */ + if (unlikely(!netif_running(dev))) { + RTL_W16 (IntrMask, 0); + goto out; + } + } + + /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ /* Acknowledge all of the current interrupt sources ASAP, but an first get an additional status bit from CSCR. */ @@ -2400,31 +2396,28 @@ link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit; ackstat = status & ~(RxAckBits | TxErr); - if (ackstat) { + if (ackstat) RTL_W16 (IntrStatus, ackstat); - } /* Receive packets are processed by poll routine. If not running start it now. */ - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - - if (status & RxAckBits) - { - if (dev != rtl_ec_net_dev) { - /* Mark for polling */ - if (netif_rx_schedule_prep(dev)) { - RTL_W16_F (IntrMask, rtl8139_norx_intr_mask); - __netif_rx_schedule (dev); - } + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + + if (status & RxAckBits){ + if (dev != rtl_ec_net_dev) { + /* Mark for polling */ + if (netif_rx_schedule_prep(dev)) { + RTL_W16_F (IntrMask, rtl8139_norx_intr_mask); + __netif_rx_schedule (dev); } - else { - /* EtherCAT device: Just receive all frames */ - rtl8139_rx(dev, tp, 100); // FIXME - } - } - - /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + } else { + /* EtherCAT device: Just receive all frames */ + rtl8139_rx(dev, tp, 100); // FIXME + } + } + + /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ /* Check uncommon events with one test. */ if (unlikely(status & (PCIErr | PCSTimeout | RxUnderrun | RxErr))) @@ -2437,13 +2430,14 @@ RTL_W16 (IntrStatus, TxErr); } out: - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ if (dev != rtl_ec_net_dev) { - spin_unlock (&tp->lock); - } - - /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + spin_unlock (&tp->lock); + } + + /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, RTL_R16 (IntrStatus)); @@ -2470,55 +2464,55 @@ int ret = 0; unsigned long flags; - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - - if (dev != rtl_ec_net_dev) { - netif_stop_queue(dev); - if (tp->thr_pid >= 0) { - tp->time_to_die = 1; - wmb(); - ret = kill_proc (tp->thr_pid, SIGTERM, 1); - if (ret) { - printk (KERN_ERR "%s: unable to signal thread\n", dev->name); - return ret; - } - wait_for_completion (&tp->thr_exited); + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + + if (dev != rtl_ec_net_dev) { + netif_stop_queue (dev); + + if (tp->thr_pid >= 0) { + tp->time_to_die = 1; + wmb(); + ret = kill_proc (tp->thr_pid, SIGTERM, 1); + if (ret) { + printk (KERN_ERR "%s: unable to signal thread\n", dev->name); + return ret; } - - if (netif_msg_ifdown(tp)) - printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n", - dev->name, RTL_R16 (IntrStatus)); - - spin_lock_irqsave (&tp->lock, flags); - - /* Stop the chip's Tx and Rx DMA processes. */ - RTL_W8 (ChipCmd, 0); - - /* Disable interrupts by clearing the interrupt mask. */ - RTL_W16 (IntrMask, 0); - - /* Update the error counts. */ - tp->stats.rx_missed_errors += RTL_R32 (RxMissed); - RTL_W32 (RxMissed, 0); - - spin_unlock_irqrestore (&tp->lock, flags); - - synchronize_irq (dev->irq); /* racy, but that's ok here */ - free_irq (dev->irq, dev); + wait_for_completion (&tp->thr_exited); } - else { - /* Stop the chip's Tx and Rx DMA processes. */ - RTL_W8 (ChipCmd, 0); - - /* Disable interrupts by clearing the interrupt mask. */ - RTL_W16 (IntrMask, 0); - - /* Update the error counts. */ - tp->stats.rx_missed_errors += RTL_R32 (RxMissed); - RTL_W32 (RxMissed, 0); - } - - /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + + if (netif_msg_ifdown(tp)) + printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n", + dev->name, RTL_R16 (IntrStatus)); + + spin_lock_irqsave (&tp->lock, flags); + + /* Stop the chip's Tx and Rx DMA processes. */ + RTL_W8 (ChipCmd, 0); + + /* Disable interrupts by clearing the interrupt mask. */ + RTL_W16 (IntrMask, 0); + + /* Update the error counts. */ + tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + RTL_W32 (RxMissed, 0); + + spin_unlock_irqrestore (&tp->lock, flags); + + synchronize_irq (dev->irq); /* racy, but that's ok here */ + free_irq (dev->irq, dev); + } else { + /* Stop the chip's Tx and Rx DMA processes. */ + RTL_W8 (ChipCmd, 0); + + /* Disable interrupts by clearing the interrupt mask. */ + RTL_W16 (IntrMask, 0); + + /* Update the error counts. */ + tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + RTL_W32 (RxMissed, 0); + } + + /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ rtl8139_tx_clear (tp); @@ -2733,12 +2727,12 @@ struct rtl8139_private *np = netdev_priv(dev); int rc; - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - - if (dev == rtl_ec_net_dev || !netif_running(dev)) - return -EINVAL; - - /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + + if (dev == rtl_ec_net_dev || !netif_running(dev)) + return -EINVAL; + + /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ spin_lock_irq(&np->lock); rc = generic_mii_ioctl(&np->mii, if_mii(rq), cmd, NULL); @@ -2754,16 +2748,16 @@ void __iomem *ioaddr = tp->mmio_addr; unsigned long flags; - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ if (dev == rtl_ec_net_dev || netif_running(dev)) { - spin_lock_irqsave (&tp->lock, flags); - tp->stats.rx_missed_errors += RTL_R32 (RxMissed); - RTL_W32 (RxMissed, 0); - spin_unlock_irqrestore (&tp->lock, flags); - } - - /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + spin_lock_irqsave (&tp->lock, flags); + tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + RTL_W32 (RxMissed, 0); + spin_unlock_irqrestore (&tp->lock, flags); + } + + /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ return &tp->stats; } @@ -2840,12 +2834,12 @@ pci_save_state (pdev); - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ if (dev == rtl_ec_net_dev || !netif_running (dev)) - return 0; - - /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + return 0; + + /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ netif_device_detach (dev); @@ -2873,12 +2867,12 @@ pci_restore_state (pdev); - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ if (dev == rtl_ec_net_dev || !netif_running (dev)) - return 0; - - /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + return 0; + + /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ pci_set_power_state (pdev, PCI_D0); rtl8139_init_ring (dev); @@ -2928,9 +2922,8 @@ printk(KERN_ERR "Failed to start EtherCAT device!\n"); goto out_unregister; } - } - else { - printk(KERN_WARNING "NO EtherCAT device registered!\n"); + } else { + printk(KERN_WARNING "No EtherCAT device registered!\n"); } return 0; diff -r 9d7453c16ade -r 4bbe090553f7 devices/Makefile --- a/devices/Makefile Mon May 29 09:54:18 2006 +0000 +++ b/devices/Makefile Mon Jun 26 15:04:06 2006 +0000 @@ -1,6 +1,6 @@ #------------------------------------------------------------------------------ # -# kbuild Makefile +# Makefile # # IgH EtherCAT master device modules # @@ -35,39 +35,45 @@ # #------------------------------------------------------------------------------ -ifneq ($(KERNELRELEASE),) - #------------------------------------------------------------------------------ # kbuild section +ifneq ($(KERNELRELEASE),) + obj-m := ec_8139too.o ec_8139too-objs := 8139too.o -REV := $(shell svnversion $(src) 2>/dev/null) +REV := $(shell svnversion $(src) 2>/dev/null || echo "unknown") EXTRA_CFLAGS = -DEC_REV=$(REV) -DEC_USER=$(USER) #------------------------------------------------------------------------------ +# default section else -#------------------------------------------------------------------------------ -# default section - ifneq ($(wildcard ../ethercat.conf),) include ../ethercat.conf else KERNEL := $(shell uname -r) endif -KERNELDIR := /lib/modules/$(KERNEL)/build +KERNEL_DIR := /lib/modules/$(KERNEL)/build +CURRENT_DIR := $(shell pwd) +INSTALL_MOD_DIR := ethercat/devices modules: - $(MAKE) -C $(KERNELDIR) M=`pwd` + $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) modules + +install: modules_install + +modules_install: + $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) \ + INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) modules_install clean: - $(MAKE) -C $(KERNELDIR) M=`pwd` clean + $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean #------------------------------------------------------------------------------ diff -r 9d7453c16ade -r 4bbe090553f7 ethercat.conf.tmpl --- a/ethercat.conf.tmpl Mon May 29 09:54:18 2006 +0000 +++ b/ethercat.conf.tmpl Mon Jun 26 15:04:06 2006 +0000 @@ -12,6 +12,6 @@ # # The kernel to compile the EtherCAT sources against # -KERNEL := `uname -r` +KERNEL := $(shell uname -r) #------------------------------------------------------------------------------ diff -r 9d7453c16ade -r 4bbe090553f7 examples/mini/Makefile --- a/examples/mini/Makefile Mon May 29 09:54:18 2006 +0000 +++ b/examples/mini/Makefile Mon Jun 26 15:04:06 2006 +0000 @@ -56,14 +56,16 @@ ifneq ($(wildcard kernel.conf),) include kernel.conf else -KERNELDIR = /lib/modules/`uname -r`/build +KERNEL_DIR := /lib/modules/$(shell uname -r)/build endif +CURRENT_DIR := $(shell pwd) + modules: - $(MAKE) -C $(KERNELDIR) M=`pwd` + $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean: - $(MAKE) -C $(KERNELDIR) M=`pwd` clean + $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean #---------------------------------------------------------------- diff -r 9d7453c16ade -r 4bbe090553f7 examples/mini/kernel.conf.tmpl --- a/examples/mini/kernel.conf.tmpl Mon May 29 09:54:18 2006 +0000 +++ b/examples/mini/kernel.conf.tmpl Mon Jun 26 15:04:06 2006 +0000 @@ -9,4 +9,4 @@ # #------------------------------------------------------------------------------ -KERNELDIR = /lib/modules/`uname -r`/build +KERNELDIR := /lib/modules/$(shell uname -r)/build diff -r 9d7453c16ade -r 4bbe090553f7 examples/mini/mini.c --- a/examples/mini/mini.c Mon May 29 09:54:18 2006 +0000 +++ b/examples/mini/mini.c Mon Jun 26 15:04:06 2006 +0000 @@ -57,14 +57,15 @@ // data fields //void *r_ssi_input, *r_ssi_status, *r_4102[3]; +void *r_kbus_in, *r_kbus_out; // channels uint32_t k_pos; uint8_t k_stat; ec_field_init_t domain1_fields[] = { - {NULL, "3", "Beckhoff", "EL5001", "InputValue", 0}, - {NULL, "2", "Beckhoff", "EL4132", "OutputValue", 0}, + //{&r_kbus_out, "0", "Beckhoff", "BK1120", "Outputs", 0}, + //{&r_kbus_in, "0", "Beckhoff", "BK1120", "Inputs", 0}, {} }; @@ -73,6 +74,7 @@ void run(unsigned long data) { static unsigned int counter = 0; + unsigned int i; spin_lock(&master_lock); @@ -105,8 +107,9 @@ } else { counter = FREQUENCY; - //printk(KERN_INFO "k_pos = %i\n", k_pos); - //printk(KERN_INFO "k_stat = 0x%02X\n", k_stat); + printk(KERN_INFO "input = "); + for (i = 0; i < 22; i++) printk("%02X ", *((uint8_t *) r_kbus_in + i)); + printk("\n"); } // restart timer @@ -133,6 +136,8 @@ int __init init_mini_module(void) { + ec_slave_t *slave; + printk(KERN_INFO "=== Starting Minimal EtherCAT environment... ===\n"); if ((master = ecrt_request_master(0)) == NULL) { @@ -155,13 +160,23 @@ goto out_release_master; } +#if 1 + printk(KERN_INFO "Setting variable data field sizes...\n"); + if (!(slave = ecrt_master_get_slave(master, "0"))) { + printk(KERN_ERR "Failed to get slave!\n"); + goto out_deactivate; + } + ecrt_slave_field_size(slave, "Outputs", 0, 0x16); + ecrt_slave_field_size(slave, "Inputs", 0, 0x16); +#endif + printk(KERN_INFO "Activating master...\n"); if (ecrt_master_activate(master)) { printk(KERN_ERR "Failed to activate master!\n"); goto out_release_master; } -#if 0 +#if 1 if (ecrt_master_fetch_sdo_lists(master)) { printk(KERN_ERR "Failed to fetch SDO lists!\n"); goto out_deactivate; @@ -191,14 +206,6 @@ } #endif -#if 0 - printk(KERN_INFO "Writing alias...\n"); - if (ecrt_slave_sdo_write_exp16(slave, 0xBEEF)) { - printk(KERN_ERR "Failed to write alias!\n"); - goto out_deactivate; - } -#endif - #ifdef ASYNC // send once and wait... ecrt_master_prepare_async_io(master); diff -r 9d7453c16ade -r 4bbe090553f7 examples/msr/Makefile --- a/examples/msr/Makefile Mon May 29 09:54:18 2006 +0000 +++ b/examples/msr/Makefile Mon Jun 26 15:04:06 2006 +0000 @@ -75,13 +75,14 @@ KERNEL := $(shell uname -r) endif -KERNELDIR := /lib/modules/$(KERNEL)/build +KERNEL_DIR := /lib/modules/$(KERNEL)/build +CURRENT_DIR := $(shell pwd) modules: - $(MAKE) -C $(KERNELDIR) M=`pwd` + $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean: - $(MAKE) -C $(KERNELDIR) M=`pwd` clean + $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean install: @./install.sh $(MODULE) $(KERNEL) diff -r 9d7453c16ade -r 4bbe090553f7 examples/msr/kernel.conf.tmpl --- a/examples/msr/kernel.conf.tmpl Mon May 29 09:54:18 2006 +0000 +++ b/examples/msr/kernel.conf.tmpl Mon Jun 26 15:04:06 2006 +0000 @@ -10,6 +10,6 @@ #------------------------------------------------------------------------------ # Kernel sources for module compilation -KERNEL := `uname -r` +KERNEL := $(shell uname -r) #------------------------------------------------------------------------------ diff -r 9d7453c16ade -r 4bbe090553f7 examples/rtai/Makefile --- a/examples/rtai/Makefile Mon May 29 09:54:18 2006 +0000 +++ b/examples/rtai/Makefile Mon Jun 26 15:04:06 2006 +0000 @@ -58,14 +58,16 @@ ifneq ($(wildcard kernel.conf),) include kernel.conf else -KERNELDIR = /lib/modules/`uname -r`/build +KERNEL_DIR := /lib/modules/$(shell uname -r)/build endif +CURRENT_DIR := $(shell pwd) + modules: - $(MAKE) -C $(KERNELDIR) M=`pwd` + $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean: - $(MAKE) -C $(KERNELDIR) M=`pwd` clean + $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean #------------------------------------------------------------------------------ diff -r 9d7453c16ade -r 4bbe090553f7 examples/rtai/kernel.conf.tmpl --- a/examples/rtai/kernel.conf.tmpl Mon May 29 09:54:18 2006 +0000 +++ b/examples/rtai/kernel.conf.tmpl Mon Jun 26 15:04:06 2006 +0000 @@ -9,4 +9,4 @@ # #------------------------------------------------------------------------------ -KERNELDIR = /lib/modules/`uname -r`/build +KERNELDIR := /lib/modules/$(shell uname -r)/build diff -r 9d7453c16ade -r 4bbe090553f7 include/ecrt.h --- a/include/ecrt.h Mon May 29 09:54:18 2006 +0000 +++ b/include/ecrt.h Mon Jun 26 15:04:06 2006 +0000 @@ -145,6 +145,8 @@ * Slave Methods *****************************************************************************/ +/* there SDO functions are deprecated! */ + int ecrt_slave_sdo_read_exp8(ec_slave_t *slave, uint16_t sdo_index, uint8_t sdo_subindex, uint8_t *value); int ecrt_slave_sdo_read_exp16(ec_slave_t *slave, uint16_t sdo_index, @@ -160,7 +162,10 @@ int ecrt_slave_sdo_read(ec_slave_t *slave, uint16_t sdo_index, uint8_t sdo_subindex, uint8_t *data, size_t *size); -int ecrt_slave_write_alias(ec_slave_t *slave, uint16_t alias); +int ecrt_slave_write_alias(ec_slave_t *slave, uint16_t alias); // deprecated! + +int ecrt_slave_field_size(ec_slave_t *slave, const char *field_name, + unsigned int field_index, size_t size); /****************************************************************************** * Bitwise read/write macros diff -r 9d7453c16ade -r 4bbe090553f7 master/Makefile --- a/master/Makefile Mon May 29 09:54:18 2006 +0000 +++ b/master/Makefile Mon Jun 26 15:04:06 2006 +0000 @@ -35,40 +35,46 @@ # #------------------------------------------------------------------------------ -ifneq ($(KERNELRELEASE),) - #------------------------------------------------------------------------------ # kbuild section +ifneq ($(KERNELRELEASE),) + obj-m := ec_master.o ec_master-objs := module.o master.o device.o slave.o command.o types.o \ domain.o mailbox.o canopen.o ethernet.o debug.o fsm.o -REV := $(shell svnversion $(src) 2>/dev/null) +REV := $(shell svnversion $(src) 2>/dev/null || echo "unknown") EXTRA_CFLAGS := -DSVNREV=$(REV) -DUSER=$(USER) #------------------------------------------------------------------------------ +# default section else -#------------------------------------------------------------------------------ -# default section - ifneq ($(wildcard ../ethercat.conf),) include ../ethercat.conf else KERNEL := $(shell uname -r) endif -KERNELDIR := /lib/modules/$(KERNEL)/build +KERNEL_DIR := /lib/modules/$(KERNEL)/build +CURRENT_DIR := $(shell pwd) +INSTALL_MOD_DIR := ethercat/master modules: - $(MAKE) -C $(KERNELDIR) M=`pwd` + $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) modules + +install: modules_install + +modules_install: + $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) \ + INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) modules_install clean: - $(MAKE) -C $(KERNELDIR) M=`pwd` clean + $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean #------------------------------------------------------------------------------ diff -r 9d7453c16ade -r 4bbe090553f7 master/canopen.c --- a/master/canopen.c Mon May 29 09:54:18 2006 +0000 +++ b/master/canopen.c Mon Jun 26 15:04:06 2006 +0000 @@ -48,8 +48,9 @@ /*****************************************************************************/ void ec_canopen_abort_msg(uint32_t); -int ec_slave_fetch_sdo_descriptions(ec_slave_t *); -int ec_slave_fetch_sdo_entries(ec_slave_t *, ec_sdo_t *, uint8_t); +int ec_slave_fetch_sdo_descriptions(ec_slave_t *, ec_command_t *); +int ec_slave_fetch_sdo_entries(ec_slave_t *, ec_command_t *, + ec_sdo_t *, uint8_t); /*****************************************************************************/ @@ -68,10 +69,14 @@ uint8_t *target /**< 4-byte memory */ ) { + ec_command_t command; size_t rec_size; uint8_t *data; - if (!(data = ec_slave_mbox_prepare_send(slave, 0x03, 6))) return -1; + ec_command_init(&command); + + if (!(data = ec_slave_mbox_prepare_send(slave, &command, 0x03, 6))) + goto err; EC_WRITE_U16(data, 0x2 << 12); // SDO request EC_WRITE_U8 (data + 2, (0x1 << 1 // expedited transfer @@ -79,14 +84,15 @@ EC_WRITE_U16(data + 3, sdo_index); EC_WRITE_U8 (data + 5, sdo_subindex); - if (!(data = ec_slave_mbox_simple_io(slave, &rec_size))) return -1; + if (!(data = ec_slave_mbox_simple_io(slave, &command, &rec_size))) + goto err; if (EC_READ_U16(data) >> 12 == 0x2 && // SDO request EC_READ_U8 (data + 2) >> 5 == 0x4) { // abort SDO transfer request EC_ERR("SDO upload 0x%04X:%X aborted on slave %i.\n", sdo_index, sdo_subindex, slave->ring_position); ec_canopen_abort_msg(EC_READ_U32(data + 6)); - return -1; + goto err; } if (EC_READ_U16(data) >> 12 != 0x3 || // SDO response @@ -97,11 +103,16 @@ EC_ERR("Invalid SDO upload response at slave %i!\n", slave->ring_position); ec_print_data(data, rec_size); - return -1; + goto err; } memcpy(target, data + 6, 4); - return 0; + + ec_command_clear(&command); + return 0; + err: + ec_command_clear(&command); + return -1; } /*****************************************************************************/ @@ -120,13 +131,17 @@ { uint8_t *data; size_t rec_size; + ec_command_t command; + + ec_command_init(&command); if (size == 0 || size > 4) { EC_ERR("Invalid data size!\n"); - return -1; - } - - if (!(data = ec_slave_mbox_prepare_send(slave, 0x03, 0x0A))) return -1; + goto err; + } + + if (!(data = ec_slave_mbox_prepare_send(slave, &command, 0x03, 0x0A))) + goto err; EC_WRITE_U16(data, 0x2 << 12); // SDO request EC_WRITE_U8 (data + 2, (0x1 // size specified @@ -138,7 +153,8 @@ memcpy(data + 6, sdo_data, size); if (size < 4) memset(data + 6 + size, 0x00, 4 - size); - if (!(data = ec_slave_mbox_simple_io(slave, &rec_size))) return -1; + if (!(data = ec_slave_mbox_simple_io(slave, &command, &rec_size))) + goto err; if (EC_READ_U16(data) >> 12 == 0x2 && // SDO request EC_READ_U8 (data + 2) >> 5 == 0x4) { // abort SDO transfer request @@ -160,7 +176,11 @@ return -1; } - return 0; + ec_command_clear(&command); + return 0; + err: + ec_command_clear(&command); + return -1; } /*****************************************************************************/ @@ -182,22 +202,27 @@ uint8_t *data; size_t rec_size, data_size; uint32_t complete_size; - - if (!(data = ec_slave_mbox_prepare_send(slave, 0x03, 6))) return -1; + ec_command_t command; + + ec_command_init(&command); + + if (!(data = ec_slave_mbox_prepare_send(slave, &command, 0x03, 6))) + goto err; EC_WRITE_U16(data, 0x2 << 12); // SDO request EC_WRITE_U8 (data + 2, 0x2 << 5); // initiate upload request EC_WRITE_U16(data + 3, sdo_index); EC_WRITE_U8 (data + 5, sdo_subindex); - if (!(data = ec_slave_mbox_simple_io(slave, &rec_size))) return -1; + if (!(data = ec_slave_mbox_simple_io(slave, &command, &rec_size))) + goto err; if (EC_READ_U16(data) >> 12 == 0x2 && // SDO request EC_READ_U8 (data + 2) >> 5 == 0x4) { // abort SDO transfer request EC_ERR("SDO upload 0x%04X:%X aborted on slave %i.\n", sdo_index, sdo_subindex, slave->ring_position); ec_canopen_abort_msg(EC_READ_U32(data + 6)); - return -1; + goto err; } if (EC_READ_U16(data) >> 12 != 0x3 || // SDO response @@ -208,30 +233,35 @@ EC_ERR("Invalid SDO upload response at slave %i!\n", slave->ring_position); ec_print_data(data, rec_size); - return -1; + goto err; } if (rec_size < 10) { EC_ERR("Received currupted SDO upload response!\n"); ec_print_data(data, rec_size); - return -1; + goto err; } if ((complete_size = EC_READ_U32(data + 6)) > *size) { EC_ERR("SDO data does not fit into buffer (%i / %i)!\n", complete_size, *size); - return -1; + goto err; } data_size = rec_size - 10; if (data_size != complete_size) { EC_ERR("SDO data incomplete - Fragmenting not implemented.\n"); - return -1; + goto err; } memcpy(target, data + 10, data_size); - return 0; + + ec_command_clear(&command); + return 0; + err: + ec_command_clear(&command); + return -1; } /*****************************************************************************/ @@ -248,8 +278,12 @@ unsigned int i, sdo_count; ec_sdo_t *sdo; uint16_t sdo_index; - - if (!(data = ec_slave_mbox_prepare_send(slave, 0x03, 8))) return -1; + ec_command_t command; + + ec_command_init(&command); + + if (!(data = ec_slave_mbox_prepare_send(slave, &command, 0x03, 8))) + goto err; EC_WRITE_U16(data, 0x8 << 12); // SDO information EC_WRITE_U8 (data + 2, 0x01); // Get OD List Request @@ -257,21 +291,22 @@ EC_WRITE_U16(data + 4, 0x0000); EC_WRITE_U16(data + 6, 0x0001); // deliver all SDOs! - if (unlikely(ec_master_simple_io(slave->master, &slave->mbox_command))) { + if (unlikely(ec_master_simple_io(slave->master, &command))) { EC_ERR("Mailbox checking failed on slave %i!\n", slave->ring_position); - return -1; + goto err; } do { - if (!(data = ec_slave_mbox_simple_receive(slave, 0x03, &rec_size))) - return -1; + if (!(data = ec_slave_mbox_simple_receive(slave, &command, + 0x03, &rec_size))) + goto err; if (EC_READ_U16(data) >> 12 == 0x8 && // SDO information (EC_READ_U8(data + 2) & 0x7F) == 0x07) { // error response EC_ERR("SDO information error response at slave %i!\n", slave->ring_position); ec_canopen_abort_msg(EC_READ_U32(data + 6)); - return -1; + goto err; } if (EC_READ_U16(data) >> 12 != 0x8 || // SDO information @@ -279,13 +314,13 @@ EC_ERR("Invalid SDO list response at slave %i!\n", slave->ring_position); ec_print_data(data, rec_size); - return -1; + goto err; } if (rec_size < 8) { EC_ERR("Invalid data size!\n"); ec_print_data(data, rec_size); - return -1; + goto err; } sdo_count = (rec_size - 8) / 2; @@ -295,7 +330,7 @@ if (!(sdo = (ec_sdo_t *) kmalloc(sizeof(ec_sdo_t), GFP_KERNEL))) { EC_ERR("Failed to allocate memory for SDO!\n"); - return -1; + goto err; } // Initialize SDO object @@ -311,9 +346,13 @@ while (EC_READ_U8(data + 2) & 0x80); // Fetch all SDO descriptions - if (ec_slave_fetch_sdo_descriptions(slave)) return -1; - - return 0; + if (ec_slave_fetch_sdo_descriptions(slave, &command)) goto err; + + ec_command_clear(&command); + return 0; + err: + ec_command_clear(&command); + return -1; } /*****************************************************************************/ @@ -323,21 +362,25 @@ \return 0 in case of success, else < 0 */ -int ec_slave_fetch_sdo_descriptions(ec_slave_t *slave /**< EtherCAT slave */) +int ec_slave_fetch_sdo_descriptions(ec_slave_t *slave, /**< EtherCAT slave */ + ec_command_t *command /**< command */ + ) { uint8_t *data; size_t rec_size, name_size; ec_sdo_t *sdo; list_for_each_entry(sdo, &slave->sdo_dictionary, list) { - if (!(data = ec_slave_mbox_prepare_send(slave, 0x03, 8))) return -1; + if (!(data = ec_slave_mbox_prepare_send(slave, command, 0x03, 8))) + return -1; EC_WRITE_U16(data, 0x8 << 12); // SDO information EC_WRITE_U8 (data + 2, 0x03); // Get object description request EC_WRITE_U8 (data + 3, 0x00); EC_WRITE_U16(data + 4, 0x0000); EC_WRITE_U16(data + 6, sdo->index); // SDO index - if (!(data = ec_slave_mbox_simple_io(slave, &rec_size))) return -1; + if (!(data = ec_slave_mbox_simple_io(slave, command, &rec_size))) + return -1; if (EC_READ_U16(data) >> 12 == 0x8 && // SDO information (EC_READ_U8 (data + 2) & 0x7F) == 0x07) { // error response @@ -364,8 +407,10 @@ return -1; } +#if 0 EC_DBG("object desc response:\n"); ec_print_data(data, rec_size); +#endif //sdo->unknown = EC_READ_U16(data + 8); sdo->object_code = EC_READ_U8(data + 11); @@ -387,7 +432,8 @@ } // Fetch all entries (subindices) - if (ec_slave_fetch_sdo_entries(slave, sdo, EC_READ_U8(data + 10))) + if (ec_slave_fetch_sdo_entries(slave, command, sdo, + EC_READ_U8(data + 10))) return -1; } @@ -402,6 +448,7 @@ */ int ec_slave_fetch_sdo_entries(ec_slave_t *slave, /**< EtherCAT slave */ + ec_command_t *command, /**< command */ ec_sdo_t *sdo, /**< SDO */ uint8_t subindices /**< number of subindices */ ) @@ -412,7 +459,7 @@ ec_sdo_entry_t *entry; for (i = 1; i <= subindices; i++) { - if (!(data = ec_slave_mbox_prepare_send(slave, 0x03, 10))) + if (!(data = ec_slave_mbox_prepare_send(slave, command, 0x03, 10))) return -1; EC_WRITE_U16(data, 0x8 << 12); // SDO information @@ -423,7 +470,8 @@ EC_WRITE_U8 (data + 8, i); // SDO subindex EC_WRITE_U8 (data + 9, 0x00); // value info (no values) - if (!(data = ec_slave_mbox_simple_io(slave, &rec_size))) return -1; + if (!(data = ec_slave_mbox_simple_io(slave, command, &rec_size))) + return -1; if (EC_READ_U16(data) >> 12 == 0x8 && // SDO information (EC_READ_U8 (data + 2) & 0x7F) == 0x07) { // error response diff -r 9d7453c16ade -r 4bbe090553f7 master/domain.c --- a/master/domain.c Mon May 29 09:54:18 2006 +0000 +++ b/master/domain.c Mon Jun 26 15:04:06 2006 +0000 @@ -225,7 +225,7 @@ */ int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */ - uint32_t base_address /**< Logische Basisadresse */ + uint32_t base_address /**< logical base address */ ) { ec_field_reg_t *field_reg; @@ -234,12 +234,12 @@ unsigned int i, j, cmd_count; uint32_t field_off, field_off_cmd; uint32_t cmd_offset; - size_t cmd_data_size; + size_t cmd_data_size, sync_size; ec_command_t *command; domain->base_address = base_address; - // Größe der Prozessdaten berechnen und Kommandos allozieren + // calculate size of process data and allocate memory domain->data_size = 0; cmd_offset = base_address; cmd_data_size = 0; @@ -249,20 +249,21 @@ fmmu = &slave->fmmus[j]; if (fmmu->domain == domain) { fmmu->logical_start_address = base_address + domain->data_size; - domain->data_size += fmmu->sync->size; - if (cmd_data_size + fmmu->sync->size > EC_MAX_DATA_SIZE) { + sync_size = ec_slave_calc_sync_size(slave, fmmu->sync); + domain->data_size += sync_size; + if (cmd_data_size + sync_size > EC_MAX_DATA_SIZE) { if (ec_domain_add_command(domain, cmd_offset, cmd_data_size)) return -1; cmd_offset += cmd_data_size; cmd_data_size = 0; cmd_count++; } - cmd_data_size += fmmu->sync->size; + cmd_data_size += sync_size; } } } - // Letztes Kommando allozieren + // allocate last command if (cmd_data_size) { if (ec_domain_add_command(domain, cmd_offset, cmd_data_size)) return -1; @@ -275,14 +276,14 @@ return 0; } - // Alle Prozessdatenzeiger setzen + // set all process data pointers list_for_each_entry(field_reg, &domain->field_regs, list) { for (i = 0; i < field_reg->slave->fmmu_count; i++) { fmmu = &field_reg->slave->fmmus[i]; if (fmmu->domain == domain && fmmu->sync == field_reg->sync) { field_off = fmmu->logical_start_address + field_reg->field_offset; - // Kommando suchen + // search command list_for_each_entry(command, &domain->commands, list) { field_off_cmd = field_off - command->address.logical; if (field_off >= command->address.logical && diff -r 9d7453c16ade -r 4bbe090553f7 master/ethernet.c --- a/master/ethernet.c Mon May 29 09:54:18 2006 +0000 +++ b/master/ethernet.c Mon Jun 26 15:04:06 2006 +0000 @@ -79,6 +79,7 @@ int result, i; eoe->slave = NULL; + ec_command_init(&eoe->command); eoe->state = ec_eoe_state_rx_start; eoe->opened = 0; eoe->rx_skb = NULL; @@ -159,6 +160,8 @@ } if (eoe->rx_skb) dev_kfree_skb(eoe->rx_skb); + + ec_command_clear(&eoe->command); } /*****************************************************************************/ @@ -235,8 +238,8 @@ printk("\n"); #endif - if (!(data = ec_slave_mbox_prepare_send(eoe->slave, 0x02, - current_size + 4))) + if (!(data = ec_slave_mbox_prepare_send(eoe->slave, &eoe->command, + 0x02, current_size + 4))) return -1; EC_WRITE_U8 (data, 0x00); // eoe fragment req. @@ -246,7 +249,7 @@ (eoe->tx_frame_number & 0x0F) << 12)); memcpy(data + 4, eoe->tx_frame->skb->data + eoe->tx_offset, current_size); - ec_master_queue_command(eoe->slave->master, &eoe->slave->mbox_command); + ec_master_queue_command(eoe->slave->master, &eoe->command); eoe->tx_offset += current_size; eoe->tx_fragment_number++; @@ -310,8 +313,8 @@ if (!eoe->slave->online || !eoe->slave->master->device->link_state) return; - ec_slave_mbox_prepare_check(eoe->slave); - ec_master_queue_command(eoe->slave->master, &eoe->slave->mbox_command); + ec_slave_mbox_prepare_check(eoe->slave, &eoe->command); + ec_master_queue_command(eoe->slave->master, &eoe->command); eoe->state = ec_eoe_state_rx_check; } @@ -325,19 +328,19 @@ void ec_eoe_state_rx_check(ec_eoe_t *eoe /**< EoE handler */) { - if (eoe->slave->mbox_command.state != EC_CMD_RECEIVED) { + if (eoe->command.state != EC_CMD_RECEIVED) { eoe->stats.rx_errors++; eoe->state = ec_eoe_state_tx_start; return; } - if (!ec_slave_mbox_check(eoe->slave)) { + if (!ec_slave_mbox_check(&eoe->command)) { eoe->state = ec_eoe_state_tx_start; return; } - ec_slave_mbox_prepare_fetch(eoe->slave); - ec_master_queue_command(eoe->slave->master, &eoe->slave->mbox_command); + ec_slave_mbox_prepare_fetch(eoe->slave, &eoe->command); + ec_master_queue_command(eoe->slave->master, &eoe->command); eoe->state = ec_eoe_state_rx_fetch; } @@ -356,13 +359,14 @@ uint8_t frame_number, fragment_offset, fragment_number; off_t offset; - if (eoe->slave->mbox_command.state != EC_CMD_RECEIVED) { + if (eoe->command.state != EC_CMD_RECEIVED) { eoe->stats.rx_errors++; eoe->state = ec_eoe_state_tx_start; return; } - if (!(data = ec_slave_mbox_fetch(eoe->slave, 0x02, &rec_size))) { + if (!(data = ec_slave_mbox_fetch(eoe->slave, &eoe->command, + 0x02, &rec_size))) { eoe->stats.rx_errors++; eoe->state = ec_eoe_state_tx_start; return; @@ -554,13 +558,13 @@ void ec_eoe_state_tx_sent(ec_eoe_t *eoe /**< EoE handler */) { - if (eoe->slave->mbox_command.state != EC_CMD_RECEIVED) { + if (eoe->command.state != EC_CMD_RECEIVED) { eoe->stats.tx_errors++; eoe->state = ec_eoe_state_rx_start; return; } - if (eoe->slave->mbox_command.working_counter != 1) { + if (eoe->command.working_counter != 1) { eoe->stats.tx_errors++; eoe->state = ec_eoe_state_rx_start; return; diff -r 9d7453c16ade -r 4bbe090553f7 master/ethernet.h --- a/master/ethernet.h Mon May 29 09:54:18 2006 +0000 +++ b/master/ethernet.h Mon Jun 26 15:04:06 2006 +0000 @@ -73,6 +73,7 @@ { struct list_head list; /**< list item */ ec_slave_t *slave; /**< pointer to the corresponding slave */ + ec_command_t command; /**< command */ void (*state)(ec_eoe_t *); /**< state function for the state machine */ struct net_device *dev; /**< net_device for virtual ethernet device */ struct net_device_stats stats; /**< device statistics */ diff -r 9d7453c16ade -r 4bbe090553f7 master/fsm.c --- a/master/fsm.c Mon May 29 09:54:18 2006 +0000 +++ b/master/fsm.c Mon Jun 26 15:04:06 2006 +0000 @@ -44,14 +44,6 @@ /*****************************************************************************/ -/** - Size of memory to allocate while reading categories. -*/ - -#define EC_CAT_MEM 0x100 - -/*****************************************************************************/ - const ec_code_msg_t al_status_messages[]; /*****************************************************************************/ @@ -66,15 +58,15 @@ void ec_fsm_master_reconfigure(ec_fsm_t *); void ec_fsm_master_address(ec_fsm_t *); void ec_fsm_master_conf(ec_fsm_t *); +void ec_fsm_master_eeprom(ec_fsm_t *); void ec_fsm_slave_start_reading(ec_fsm_t *); void ec_fsm_slave_read_status(ec_fsm_t *); void ec_fsm_slave_read_base(ec_fsm_t *); void ec_fsm_slave_read_dl(ec_fsm_t *); -void ec_fsm_slave_prepare_sii(ec_fsm_t *); -void ec_fsm_slave_read_sii(ec_fsm_t *); -void ec_fsm_slave_category_header(ec_fsm_t *); -void ec_fsm_slave_category_data(ec_fsm_t *); +void ec_fsm_slave_eeprom_size(ec_fsm_t *); +void ec_fsm_slave_fetch_eeprom(ec_fsm_t *); +void ec_fsm_slave_fetch_eeprom2(ec_fsm_t *); void ec_fsm_slave_end(ec_fsm_t *); void ec_fsm_slave_conf(ec_fsm_t *); @@ -86,8 +78,11 @@ void ec_fsm_slave_op2(ec_fsm_t *); void ec_fsm_sii_start_reading(ec_fsm_t *); -void ec_fsm_sii_check(ec_fsm_t *); -void ec_fsm_sii_fetch(ec_fsm_t *); +void ec_fsm_sii_read_check(ec_fsm_t *); +void ec_fsm_sii_read_fetch(ec_fsm_t *); +void ec_fsm_sii_start_writing(ec_fsm_t *); +void ec_fsm_sii_write_check(ec_fsm_t *); +void ec_fsm_sii_write_check2(ec_fsm_t *); void ec_fsm_sii_end(ec_fsm_t *); void ec_fsm_sii_error(ec_fsm_t *); @@ -115,7 +110,6 @@ fsm->master_slaves_responding = 0; fsm->master_slave_states = EC_SLAVE_STATE_UNKNOWN; fsm->master_validation = 0; - fsm->slave_cat_data = NULL; ec_command_init(&fsm->command); if (ec_command_prealloc(&fsm->command, EC_MAX_DATA_SIZE)) { @@ -134,7 +128,6 @@ void ec_fsm_clear(ec_fsm_t *fsm /**< finite state machine */) { - if (fsm->slave_cat_data) kfree(fsm->slave_cat_data); ec_command_clear(&fsm->command); } @@ -149,11 +142,6 @@ fsm->master_state = ec_fsm_master_start; fsm->master_slaves_responding = 0; fsm->master_slave_states = EC_SLAVE_STATE_UNKNOWN; - - if (fsm->slave_cat_data) { - kfree(fsm->slave_cat_data); - fsm->slave_cat_data = NULL; - } } /*****************************************************************************/ @@ -422,7 +410,25 @@ return; } - // nothing to configure. restart master state machine. + if (master->mode == EC_MASTER_MODE_FREERUN) { + // nothing to configure. check for pending EEPROM write operations. + list_for_each_entry(slave, &master->slaves, list) { + if (!slave->new_eeprom_data) continue; + + // found pending EEPROM write operation. execute it! + EC_INFO("Writing EEPROM of slave %i...\n", slave->ring_position); + fsm->sii_offset = 0x0000; + memcpy(fsm->sii_value, slave->new_eeprom_data, 2); + fsm->sii_mode = 1; + fsm->sii_state = ec_fsm_sii_start_writing; + fsm->slave = slave; + fsm->master_state = ec_fsm_master_eeprom; + fsm->master_state(fsm); // execute immediately + return; + } + } + + // nothing to do. restart master state machine. fsm->master_state = ec_fsm_master_start; fsm->master_state(fsm); // execute immediately } @@ -450,7 +456,7 @@ if (fsm->sii_state != ec_fsm_sii_end) return; - if (fsm->sii_result != slave->sii_vendor_id) { + if (EC_READ_U32(fsm->sii_value) != slave->sii_vendor_id) { EC_ERR("Slave %i: invalid vendor ID!\n", slave->ring_position); fsm->master_state = ec_fsm_master_start; fsm->master_state(fsm); // execute immediately @@ -488,10 +494,10 @@ if (fsm->sii_state != ec_fsm_sii_end) return; - if (fsm->sii_result != slave->sii_product_code) { + if (EC_READ_U32(fsm->sii_value) != slave->sii_product_code) { EC_ERR("Slave %i: invalid product code!\n", slave->ring_position); EC_ERR("expected 0x%08X, got 0x%08X.\n", slave->sii_product_code, - fsm->sii_result); + EC_READ_U32(fsm->sii_value)); fsm->master_state = ec_fsm_master_start; fsm->master_state(fsm); // execute immediately return; @@ -682,6 +688,49 @@ fsm->master_state(fsm); // execute immediately } +/*****************************************************************************/ + +/** + Master state: EEPROM. +*/ + +void ec_fsm_master_eeprom(ec_fsm_t *fsm /**< finite state machine */) +{ + ec_slave_t *slave = fsm->slave; + + fsm->sii_state(fsm); // execute SII state machine + + if (fsm->sii_state == ec_fsm_sii_error) { + EC_ERR("Failed to write EEPROM contents to slave %i.\n", + slave->ring_position); + kfree(slave->new_eeprom_data); + slave->new_eeprom_data = NULL; + fsm->master_state = ec_fsm_master_start; + fsm->master_state(fsm); // execute immediately + return; + } + + if (fsm->sii_state != ec_fsm_sii_end) return; + + fsm->sii_offset++; + if (fsm->sii_offset < slave->new_eeprom_size) { + memcpy(fsm->sii_value, slave->new_eeprom_data + fsm->sii_offset, 2); + fsm->sii_state = ec_fsm_sii_start_writing; + fsm->sii_state(fsm); // execute immediately + return; + } + + // finished writing EEPROM + EC_INFO("Finished writing EEPROM of slave %i.\n", slave->ring_position); + kfree(slave->new_eeprom_data); + slave->new_eeprom_data = NULL; + + // restart master state machine. + fsm->master_state = ec_fsm_master_start; + fsm->master_state(fsm); // execute immediately + return; +} + /****************************************************************************** * slave state machine *****************************************************************************/ @@ -787,16 +836,17 @@ // read data link status ec_command_nprd(command, slave->station_address, 0x0110, 2); ec_master_queue_command(slave->master, command); - fsm->slave_state = ec_fsm_slave_prepare_sii; -} - -/*****************************************************************************/ - -/** - Slave state: PREPARE_SII. -*/ - -void ec_fsm_slave_prepare_sii(ec_fsm_t *fsm /**< finite state machine */) + fsm->slave_state = ec_fsm_slave_eeprom_size; +} + +/*****************************************************************************/ + +/** + Slave state: EEPROM_SIZE. + Read the actual size of the EEPROM to allocate the EEPROM image. +*/ + +void ec_fsm_slave_eeprom_size(ec_fsm_t *fsm /**< finite state machine */) { ec_command_t *command = &fsm->command; ec_slave_t *slave = fsm->slave; @@ -811,254 +861,183 @@ } dl_status = EC_READ_U16(command->data); - for (i = 0; i < 4; i++) { slave->dl_link[i] = dl_status & (1 << (4 + i)) ? 1 : 0; slave->dl_loop[i] = dl_status & (1 << (8 + i * 2)) ? 1 : 0; slave->dl_signal[i] = dl_status & (1 << (9 + i * 2)) ? 1 : 0; } - fsm->sii_offset = 0x0004; + // Start fetching EEPROM size + + fsm->sii_offset = 0x0040; // first category header fsm->sii_mode = 1; fsm->sii_state = ec_fsm_sii_start_reading; - fsm->slave_sii_num = 0; - fsm->slave_state = ec_fsm_slave_read_sii; + fsm->slave_state = ec_fsm_slave_fetch_eeprom; fsm->slave_state(fsm); // execute state immediately } /*****************************************************************************/ /** - Slave state: READ_SII. -*/ - -void ec_fsm_slave_read_sii(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_slave_t *slave = fsm->slave; + Slave state: FETCH_EEPROM. +*/ + +void ec_fsm_slave_fetch_eeprom(ec_fsm_t *fsm /**< finite state machine */) +{ + ec_slave_t *slave = fsm->slave; + uint16_t cat_type, cat_size; // execute SII state machine fsm->sii_state(fsm); if (fsm->sii_state == ec_fsm_sii_error) { fsm->slave_state = ec_fsm_slave_end; - EC_ERR("FSM failed to read SII data at 0x%04X on slave %i.\n", - fsm->sii_offset, slave->ring_position); + EC_ERR("Failed to read EEPROM size of slave %i.\n", + slave->ring_position); return; } if (fsm->sii_state != ec_fsm_sii_end) return; - switch (fsm->slave_sii_num) { - case 0: - slave->sii_alias = fsm->sii_result & 0xFFFF; - fsm->sii_offset = 0x0008; - break; - case 1: - slave->sii_vendor_id = fsm->sii_result; - fsm->sii_offset = 0x000A; - break; - case 2: - slave->sii_product_code = fsm->sii_result; - fsm->sii_offset = 0x000C; - break; - case 3: - slave->sii_revision_number = fsm->sii_result; - fsm->sii_offset = 0x000E; - break; - case 4: - slave->sii_serial_number = fsm->sii_result; - fsm->sii_offset = 0x0018; - break; - case 5: - slave->sii_rx_mailbox_offset = fsm->sii_result & 0xFFFF; - slave->sii_rx_mailbox_size = fsm->sii_result >> 16; - fsm->sii_offset = 0x001A; - break; - case 6: - slave->sii_tx_mailbox_offset = fsm->sii_result & 0xFFFF; - slave->sii_tx_mailbox_size = fsm->sii_result >> 16; - fsm->sii_offset = 0x001C; - break; - case 7: - slave->sii_mailbox_protocols = fsm->sii_result & 0xFFFF; - - fsm->slave_cat_offset = 0x0040; - - if (fsm->slave_cat_data) { - EC_INFO("FSM freeing old category data on slave %i...\n", - fsm->slave->ring_position); - kfree(fsm->slave_cat_data); - } - - if (!(fsm->slave_cat_data = - (uint8_t *) kmalloc(EC_CAT_MEM, GFP_ATOMIC))) { - EC_ERR("FSM Failed to allocate category data.\n"); - fsm->slave_state = ec_fsm_slave_end; - return; - } - - // start reading first category header - fsm->sii_offset = fsm->slave_cat_offset; - fsm->sii_state = ec_fsm_sii_start_reading; - - fsm->slave_state = ec_fsm_slave_category_header; - fsm->slave_state(fsm); // execute state immediately - return; - } - - fsm->slave_sii_num++; + cat_type = EC_READ_U16(fsm->sii_value); + cat_size = EC_READ_U16(fsm->sii_value + 2); + + if (cat_type != 0xFFFF) { // not the last category + fsm->sii_offset += cat_size + 2; + fsm->sii_state = ec_fsm_sii_start_reading; + fsm->sii_state(fsm); // execute state immediately + return; + } + + slave->eeprom_size = (fsm->sii_offset + 1) * 2; + + if (slave->eeprom_data) { + EC_INFO("Freeing old EEPROM data on slave %i...\n", + slave->ring_position); + kfree(slave->eeprom_data); + } + + if (!(slave->eeprom_data = + (uint8_t *) kmalloc(slave->eeprom_size, GFP_ATOMIC))) { + EC_ERR("Failed to allocate EEPROM data on slave %i.\n", + slave->ring_position); + fsm->slave_state = ec_fsm_slave_end; + return; + } + + // Start fetching EEPROM contents + + fsm->sii_offset = 0x0000; + fsm->sii_mode = 1; fsm->sii_state = ec_fsm_sii_start_reading; + fsm->slave_state = ec_fsm_slave_fetch_eeprom2; fsm->slave_state(fsm); // execute state immediately } /*****************************************************************************/ /** - Slave state: CATEGORY_HEADER. - Start reading categories. -*/ - -void ec_fsm_slave_category_header(ec_fsm_t *fsm /**< finite state machine */) -{ + Slave state: FETCH_EEPROM2. +*/ + +void ec_fsm_slave_fetch_eeprom2(ec_fsm_t *fsm /**< finite state machine */) +{ + ec_slave_t *slave = fsm->slave; + uint16_t *cat_word, cat_type, cat_size; + // execute SII state machine fsm->sii_state(fsm); if (fsm->sii_state == ec_fsm_sii_error) { - kfree(fsm->slave_cat_data); - fsm->slave_cat_data = NULL; fsm->slave_state = ec_fsm_slave_end; - EC_ERR("FSM failed to read category header at 0x%04X on slave %i.\n", - fsm->slave_cat_offset, fsm->slave->ring_position); + EC_ERR("Failed to fetch EEPROM contents of slave %i.\n", + slave->ring_position); return; } if (fsm->sii_state != ec_fsm_sii_end) return; - // last category? - if ((fsm->sii_result & 0xFFFF) == 0xFFFF) { - kfree(fsm->slave_cat_data); - fsm->slave_cat_data = NULL; - fsm->slave_state = ec_fsm_slave_end; - return; - } - - fsm->slave_cat_type = fsm->sii_result & 0x7FFF; - fsm->slave_cat_words = (fsm->sii_result >> 16) & 0xFFFF; - - if (fsm->slave_cat_words > EC_CAT_MEM * 2) { - EC_ERR("FSM category memory too small! %i words needed.\n", - fsm->slave_cat_words); - fsm->slave_state = ec_fsm_slave_end; - return; - } - - // start reading category data - fsm->slave_cat_data_offset = 0; - fsm->sii_offset = (fsm->slave_cat_offset + 2 + - fsm->slave_cat_data_offset); - fsm->sii_mode = 1; - fsm->sii_state = ec_fsm_sii_start_reading; - fsm->slave_state = ec_fsm_slave_category_data; - fsm->slave_state(fsm); // execute state immediately -} - -/*****************************************************************************/ - -/** - Slave state: CATEGORY_DATA. - Reads category data. -*/ - -void ec_fsm_slave_category_data(ec_fsm_t *fsm /**< finite state machine */) -{ - // execute SII state machine - fsm->sii_state(fsm); - - if (fsm->sii_state == ec_fsm_sii_error) { - kfree(fsm->slave_cat_data); - fsm->slave_cat_data = NULL; - fsm->slave_state = ec_fsm_slave_end; - EC_ERR("FSM failed to read category 0x%02X data at 0x%04X" - " on slave %i.\n", fsm->slave_cat_type, fsm->sii_offset, - fsm->slave->ring_position); - return; - } - - if (fsm->sii_state != ec_fsm_sii_end) return; - - fsm->slave_cat_data[fsm->slave_cat_data_offset * 2] = - fsm->sii_result & 0xFF; - fsm->slave_cat_data[fsm->slave_cat_data_offset * 2 + 1] = - (fsm->sii_result >> 8) & 0xFF; - - // read second word "on the fly" - if (fsm->slave_cat_data_offset + 1 < fsm->slave_cat_words) { - fsm->slave_cat_data_offset++; - fsm->slave_cat_data[fsm->slave_cat_data_offset * 2] = - (fsm->sii_result >> 16) & 0xFF; - fsm->slave_cat_data[fsm->slave_cat_data_offset * 2 + 1] = - (fsm->sii_result >> 24) & 0xFF; - } - - fsm->slave_cat_data_offset++; - - if (fsm->slave_cat_data_offset < fsm->slave_cat_words) { - fsm->sii_offset = (fsm->slave_cat_offset + 2 + - fsm->slave_cat_data_offset); - fsm->sii_mode = 1; + // 2 words fetched + + if (fsm->sii_offset + 2 <= slave->eeprom_size / 2) { // 2 words fit + memcpy(slave->eeprom_data + fsm->sii_offset * 2, fsm->sii_value, 4); + } + else { // copy the last word + memcpy(slave->eeprom_data + fsm->sii_offset * 2, fsm->sii_value, 2); + } + + if (fsm->sii_offset + 2 < slave->eeprom_size / 2) { + // fetch the next 2 words + fsm->sii_offset += 2; fsm->sii_state = ec_fsm_sii_start_reading; - fsm->slave_state = ec_fsm_slave_category_data; - fsm->slave_state(fsm); // execute state immediately - return; - } - - // category data complete - switch (fsm->slave_cat_type) - { - case 0x000A: - if (ec_slave_fetch_strings(fsm->slave, fsm->slave_cat_data)) - goto out_free; - break; - case 0x001E: - if (ec_slave_fetch_general(fsm->slave, fsm->slave_cat_data)) - goto out_free; - break; - case 0x0028: - break; - case 0x0029: - if (ec_slave_fetch_sync(fsm->slave, fsm->slave_cat_data, - fsm->slave_cat_words)) - goto out_free; - break; - case 0x0032: - if (ec_slave_fetch_pdo(fsm->slave, fsm->slave_cat_data, - fsm->slave_cat_words, - EC_TX_PDO)) - goto out_free; - break; - case 0x0033: - if (ec_slave_fetch_pdo(fsm->slave, fsm->slave_cat_data, - fsm->slave_cat_words, - EC_RX_PDO)) - goto out_free; - break; - default: - EC_WARN("FSM: Unknown category type 0x%04X in slave %i.\n", - fsm->slave_cat_type, fsm->slave->ring_position); - } - - // start reading next category header - fsm->slave_cat_offset += 2 + fsm->slave_cat_words; - fsm->sii_offset = fsm->slave_cat_offset; - fsm->sii_mode = 1; - fsm->sii_state = ec_fsm_sii_start_reading; - fsm->slave_state = ec_fsm_slave_category_header; - fsm->slave_state(fsm); // execute state immediately - return; - - out_free: - kfree(fsm->slave_cat_data); - fsm->slave_cat_data = NULL; + fsm->sii_state(fsm); // execute state immediately + return; + } + + // Evaluate EEPROM contents + + slave->sii_alias = + EC_READ_U16(slave->eeprom_data + 2 * 0x0004); + slave->sii_vendor_id = + EC_READ_U32(slave->eeprom_data + 2 * 0x0008); + slave->sii_product_code = + EC_READ_U32(slave->eeprom_data + 2 * 0x000A); + slave->sii_revision_number = + EC_READ_U32(slave->eeprom_data + 2 * 0x000C); + slave->sii_serial_number = + EC_READ_U32(slave->eeprom_data + 2 * 0x000E); + slave->sii_rx_mailbox_offset = + EC_READ_U16(slave->eeprom_data + 2 * 0x0018); + slave->sii_rx_mailbox_size = + EC_READ_U16(slave->eeprom_data + 2 * 0x0019); + slave->sii_tx_mailbox_offset = + EC_READ_U16(slave->eeprom_data + 2 * 0x001A); + slave->sii_tx_mailbox_size = + EC_READ_U16(slave->eeprom_data + 2 * 0x001B); + slave->sii_mailbox_protocols = + EC_READ_U16(slave->eeprom_data + 2 * 0x001C); + + // evaluate category data + cat_word = (uint16_t *) slave->eeprom_data + 0x0040; + while (EC_READ_U16(cat_word) != 0xFFFF) { + cat_type = EC_READ_U16(cat_word) & 0x7FFF; + cat_size = EC_READ_U16(cat_word + 1); + + switch (cat_type) { + case 0x000A: + if (ec_slave_fetch_strings(slave, (uint8_t *) (cat_word + 2))) + goto end; + break; + case 0x001E: + if (ec_slave_fetch_general(slave, (uint8_t *) (cat_word + 2))) + goto end; + break; + case 0x0028: + break; + case 0x0029: + if (ec_slave_fetch_sync(slave, (uint8_t *) (cat_word + 2), + cat_size)) + goto end; + break; + case 0x0032: + if (ec_slave_fetch_pdo(slave, (uint8_t *) (cat_word + 2), + cat_size, EC_TX_PDO)) + goto end; + break; + case 0x0033: + if (ec_slave_fetch_pdo(slave, (uint8_t *) (cat_word + 2), + cat_size, EC_RX_PDO)) + goto end; + break; + default: + EC_WARN("Unknown category type 0x%04X in slave %i.\n", + cat_type, slave->ring_position); + } + + cat_word += cat_size + 2; + } + + end: fsm->slave_state = ec_fsm_slave_end; } @@ -1149,7 +1128,7 @@ if (slave->type) { for (j = 0; slave->type->sync_managers[j] && j < EC_MAX_SYNC; j++) { sync = slave->type->sync_managers[j]; - ec_sync_config(sync, command->data + EC_SYNC_SIZE * j); + ec_sync_config(sync, slave, command->data + EC_SYNC_SIZE * j); } } @@ -1268,7 +1247,8 @@ 0x0600, EC_FMMU_SIZE * slave->base_fmmu_count); memset(command->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count); for (j = 0; j < slave->fmmu_count; j++) { - ec_fmmu_config(&slave->fmmus[j], command->data + EC_FMMU_SIZE * j); + ec_fmmu_config(&slave->fmmus[j], slave, + command->data + EC_FMMU_SIZE * j); } ec_master_queue_command(master, command); @@ -1391,17 +1371,17 @@ EC_WRITE_U8 (command->data + 1, 0x01); // request read operation EC_WRITE_U16(command->data + 2, fsm->sii_offset); ec_master_queue_command(fsm->master, command); - fsm->sii_state = ec_fsm_sii_check; -} - -/*****************************************************************************/ - -/** - SII state: CHECK. + fsm->sii_state = ec_fsm_sii_read_check; +} + +/*****************************************************************************/ + +/** + SII state: READ_CHECK. Checks, if the SII-read-command has been sent and issues a fetch command. */ -void ec_fsm_sii_check(ec_fsm_t *fsm /**< finite state machine */) +void ec_fsm_sii_read_check(ec_fsm_t *fsm /**< finite state machine */) { ec_command_t *command = &fsm->command; @@ -1422,17 +1402,17 @@ } ec_master_queue_command(fsm->master, command); - fsm->sii_state = ec_fsm_sii_fetch; -} - -/*****************************************************************************/ - -/** - SII state: FETCH. + fsm->sii_state = ec_fsm_sii_read_fetch; +} + +/*****************************************************************************/ + +/** + SII state: READ_FETCH. Fetches the result of an SII-read command. */ -void ec_fsm_sii_fetch(ec_fsm_t *fsm /**< finite state machine */) +void ec_fsm_sii_read_fetch(ec_fsm_t *fsm /**< finite state machine */) { ec_command_t *command = &fsm->command; @@ -1477,13 +1457,93 @@ #endif // SII value received. - fsm->sii_result = EC_READ_U32(command->data + 6); + memcpy(fsm->sii_value, command->data + 6, 4); fsm->sii_state = ec_fsm_sii_end; } /*****************************************************************************/ /** + SII state: START_WRITING. + Starts reading the slave information interface. +*/ + +void ec_fsm_sii_start_writing(ec_fsm_t *fsm /**< finite state machine */) +{ + ec_command_t *command = &fsm->command; + + // initiate write operation + ec_command_npwr(command, fsm->slave->station_address, 0x502, 8); + EC_WRITE_U8 (command->data, 0x01); // enable write access + EC_WRITE_U8 (command->data + 1, 0x02); // request write operation + EC_WRITE_U32(command->data + 2, fsm->sii_offset); + memcpy(command->data + 6, fsm->sii_value, 2); + ec_master_queue_command(fsm->master, command); + fsm->sii_state = ec_fsm_sii_write_check; +} + +/*****************************************************************************/ + +/** + SII state: WRITE_CHECK. +*/ + +void ec_fsm_sii_write_check(ec_fsm_t *fsm /**< finite state machine */) +{ + ec_command_t *command = &fsm->command; + + if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { + EC_ERR("SII: Reception of write command failed.\n"); + fsm->sii_state = ec_fsm_sii_error; + return; + } + + fsm->sii_start = get_cycles(); + + // issue check/fetch command + ec_command_nprd(command, fsm->slave->station_address, 0x502, 2); + ec_master_queue_command(fsm->master, command); + fsm->sii_state = ec_fsm_sii_write_check2; +} + +/*****************************************************************************/ + +/** + SII state: WRITE_CHECK2. +*/ + +void ec_fsm_sii_write_check2(ec_fsm_t *fsm /**< finite state machine */) +{ + ec_command_t *command = &fsm->command; + + if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { + EC_ERR("SII: Reception of write check command failed.\n"); + fsm->sii_state = ec_fsm_sii_error; + return; + } + + if (EC_READ_U8(command->data + 1) & 0x82) { + // still busy... timeout? + if (get_cycles() - fsm->sii_start >= (cycles_t) 10 * cpu_khz) { + EC_ERR("SII: Write timeout.\n"); + fsm->sii_state = ec_fsm_sii_error; + } + + // issue check/fetch command again + ec_master_queue_command(fsm->master, command); + } + else if (EC_READ_U8(command->data + 1) & 0x40) { + EC_ERR("SII: Write operation failed!\n"); + fsm->sii_state = ec_fsm_sii_error; + } + else { // success + fsm->sii_state = ec_fsm_sii_end; + } +} + +/*****************************************************************************/ + +/** SII state: END. End state of the slave SII state machine. */ diff -r 9d7453c16ade -r 4bbe090553f7 master/fsm.h --- a/master/fsm.h Mon May 29 09:54:18 2006 +0000 +++ b/master/fsm.h Mon Jun 26 15:04:06 2006 +0000 @@ -67,17 +67,11 @@ unsigned int master_validation; /**< non-zero, if validation to do */ void (*slave_state)(ec_fsm_t *); /**< slave state function */ - uint8_t slave_sii_num; /**< SII value iteration counter */ - uint8_t *slave_cat_data; /**< temporary memory for category data */ - uint16_t slave_cat_offset; /**< current category word offset in EEPROM */ - uint16_t slave_cat_data_offset; /**< current offset in category data */ - uint16_t slave_cat_type; /**< type of current category */ - uint16_t slave_cat_words; /**< number of words of current category */ void (*sii_state)(ec_fsm_t *); /**< SII state function */ uint16_t sii_offset; /**< input: offset in SII */ unsigned int sii_mode; /**< SII reading done by APRD (0) or NPRD (1) */ - uint32_t sii_result; /**< output: read SII value (32bit) */ + uint8_t sii_value[4]; /**< raw SII value (32bit) */ cycles_t sii_start; /**< sii start */ void (*change_state)(ec_fsm_t *); /**< slave state change state function */ diff -r 9d7453c16ade -r 4bbe090553f7 master/mailbox.c --- a/master/mailbox.c Mon May 29 09:54:18 2006 +0000 +++ b/master/mailbox.c Mon Jun 26 15:04:06 2006 +0000 @@ -52,12 +52,12 @@ \return pointer to mailbox command data */ -uint8_t *ec_slave_mbox_prepare_send(ec_slave_t *slave, /**< slave */ +uint8_t *ec_slave_mbox_prepare_send(const ec_slave_t *slave, /**< slave */ + ec_command_t *command, /**< command */ uint8_t type, /**< mailbox protocol */ size_t size /**< size of the data */ ) { - ec_command_t *command = &slave->mbox_command; size_t total_size; if (unlikely(!slave->sii_mailbox_protocols)) { @@ -79,7 +79,7 @@ EC_WRITE_U16(command->data, size); // mailbox service data length EC_WRITE_U16(command->data + 2, slave->station_address); // station address - EC_WRITE_U8 (command->data + 4, 0x00); // hhannel & priority + EC_WRITE_U8 (command->data + 4, 0x00); // channel & priority EC_WRITE_U8 (command->data + 5, type); // underlying protocol type return command->data + 6; @@ -92,10 +92,10 @@ \return 0 in case of success, else < 0 */ -int ec_slave_mbox_prepare_check(ec_slave_t *slave /**< slave */) -{ - ec_command_t *command = &slave->mbox_command; - +int ec_slave_mbox_prepare_check(const ec_slave_t *slave, /**< slave */ + ec_command_t *command /**< command */ + ) +{ // FIXME: second sync manager? if (ec_command_nprd(command, slave->station_address, 0x808, 8)) return -1; @@ -110,9 +110,9 @@ \return 0 in case of success, else < 0 */ -int ec_slave_mbox_check(const ec_slave_t *slave /**< slave */) -{ - return EC_READ_U8(slave->mbox_command.data + 5) & 8 ? 1 : 0; +int ec_slave_mbox_check(const ec_command_t *command /**< command */) +{ + return EC_READ_U8(command->data + 5) & 8 ? 1 : 0; } /*****************************************************************************/ @@ -122,10 +122,10 @@ \return 0 in case of success, else < 0 */ -int ec_slave_mbox_prepare_fetch(ec_slave_t *slave /**< slave */) -{ - ec_command_t *command = &slave->mbox_command; - +int ec_slave_mbox_prepare_fetch(const ec_slave_t *slave, /**< slave */ + ec_command_t *command /**< command */ + ) +{ if (ec_command_nprd(command, slave->station_address, slave->sii_tx_mailbox_offset, slave->sii_tx_mailbox_size)) return -1; @@ -139,12 +139,12 @@ \return pointer to the received data */ -uint8_t *ec_slave_mbox_fetch(ec_slave_t *slave, /**< slave */ +uint8_t *ec_slave_mbox_fetch(const ec_slave_t *slave, /**< slave */ + ec_command_t *command, /**< command */ uint8_t type, /**< expected mailbox protocol */ size_t *size /**< size of the received data */ ) { - ec_command_t *command = &slave->mbox_command; size_t data_size; if ((EC_READ_U8(command->data + 5) & 0x0F) != type) { @@ -171,14 +171,13 @@ \return pointer to the received data */ -uint8_t *ec_slave_mbox_simple_io(ec_slave_t *slave, /**< slave */ +uint8_t *ec_slave_mbox_simple_io(const ec_slave_t *slave, /**< slave */ + ec_command_t *command, /**< command */ size_t *size /**< size of the received data */ ) { uint8_t type; - ec_command_t *command; - - command = &slave->mbox_command; + type = EC_READ_U8(command->data + 5); if (unlikely(ec_master_simple_io(slave->master, command))) { @@ -187,7 +186,7 @@ return NULL; } - return ec_slave_mbox_simple_receive(slave, type, size); + return ec_slave_mbox_simple_receive(slave, command, type, size); } /*****************************************************************************/ @@ -197,21 +196,20 @@ \return pointer to the received data */ -uint8_t *ec_slave_mbox_simple_receive(ec_slave_t *slave, /**< slave */ +uint8_t *ec_slave_mbox_simple_receive(const ec_slave_t *slave, /**< slave */ + ec_command_t *command, /**< command */ uint8_t type, /**< expected protocol */ size_t *size /**< received data size */ ) { cycles_t start, end, timeout; - ec_command_t *command; - - command = &slave->mbox_command; + start = get_cycles(); timeout = (cycles_t) 100 * cpu_khz; // 100ms while (1) { - if (ec_slave_mbox_prepare_check(slave)) return NULL; + if (ec_slave_mbox_prepare_check(slave, command)) return NULL; if (unlikely(ec_master_simple_io(slave->master, command))) { EC_ERR("Mailbox checking failed on slave %i!\n", slave->ring_position); @@ -220,7 +218,7 @@ end = get_cycles(); - if (ec_slave_mbox_check(slave)) + if (ec_slave_mbox_check(command)) break; // proceed with receiving data if ((end - start) >= timeout) { @@ -232,7 +230,7 @@ udelay(100); } - if (ec_slave_mbox_prepare_fetch(slave)) return NULL; + if (ec_slave_mbox_prepare_fetch(slave, command)) return NULL; if (unlikely(ec_master_simple_io(slave->master, command))) { EC_ERR("Mailbox receiving failed on slave %i!\n", slave->ring_position); @@ -243,7 +241,7 @@ EC_DBG("Mailbox receive took %ius.\n", ((u32) (end - start) * 1000 / cpu_khz)); - return ec_slave_mbox_fetch(slave, type, size); -} - -/*****************************************************************************/ + return ec_slave_mbox_fetch(slave, command, type, size); +} + +/*****************************************************************************/ diff -r 9d7453c16ade -r 4bbe090553f7 master/mailbox.h --- a/master/mailbox.h Mon May 29 09:54:18 2006 +0000 +++ b/master/mailbox.h Mon Jun 26 15:04:06 2006 +0000 @@ -45,14 +45,17 @@ /*****************************************************************************/ -uint8_t *ec_slave_mbox_prepare_send(ec_slave_t *, uint8_t, size_t); -int ec_slave_mbox_prepare_check(ec_slave_t *); -int ec_slave_mbox_check(const ec_slave_t *); -int ec_slave_mbox_prepare_fetch(ec_slave_t *); -uint8_t *ec_slave_mbox_fetch(ec_slave_t *, uint8_t, size_t *); +uint8_t *ec_slave_mbox_prepare_send(const ec_slave_t *, ec_command_t *, + uint8_t, size_t); +int ec_slave_mbox_prepare_check(const ec_slave_t *, ec_command_t *); +int ec_slave_mbox_check(const ec_command_t *); +int ec_slave_mbox_prepare_fetch(const ec_slave_t *, ec_command_t *); +uint8_t *ec_slave_mbox_fetch(const ec_slave_t *, ec_command_t *, + uint8_t, size_t *); -uint8_t *ec_slave_mbox_simple_io(ec_slave_t *, size_t *); -uint8_t *ec_slave_mbox_simple_receive(ec_slave_t *, uint8_t, size_t *); +uint8_t *ec_slave_mbox_simple_io(const ec_slave_t *, ec_command_t *, size_t *); +uint8_t *ec_slave_mbox_simple_receive(const ec_slave_t *, ec_command_t *, + uint8_t, size_t *); /*****************************************************************************/ diff -r 9d7453c16ade -r 4bbe090553f7 master/master.c --- a/master/master.c Mon May 29 09:54:18 2006 +0000 +++ b/master/master.c Mon Jun 26 15:04:06 2006 +0000 @@ -58,6 +58,8 @@ void ec_master_freerun(void *); void ec_master_eoe_run(unsigned long); ssize_t ec_show_master_attribute(struct kobject *, struct attribute *, char *); +ssize_t ec_store_master_attribute(struct kobject *, struct attribute *, + const char *, size_t); /*****************************************************************************/ @@ -65,16 +67,18 @@ EC_SYSFS_READ_ATTR(slave_count); EC_SYSFS_READ_ATTR(mode); +EC_SYSFS_READ_WRITE_ATTR(eeprom_write_enable); static struct attribute *ec_def_attrs[] = { &attr_slave_count, &attr_mode, + &attr_eeprom_write_enable, NULL, }; static struct sysfs_ops ec_sysfs_ops = { .show = &ec_show_master_attribute, - .store = NULL + .store = ec_store_master_attribute }; static struct kobj_type ktype_ec_master = { @@ -244,6 +248,8 @@ master->release_cb = NULL; master->cb_data = NULL; + master->eeprom_write_enable = 0; + ec_fsm_reset(&master->fsm); } @@ -492,7 +498,7 @@ { unsigned int response_tries_left; - response_tries_left = 10; + response_tries_left = 10000; while (1) { @@ -698,13 +704,13 @@ ec_master_eoe_stop(master); EC_INFO("Stopping Free-Run mode.\n"); + master->mode = EC_MASTER_MODE_IDLE; if (!cancel_delayed_work(&master->freerun_work)) { flush_workqueue(master->workqueue); } ec_master_clear_slaves(master); - master->mode = EC_MASTER_MODE_IDLE; } /*****************************************************************************/ @@ -730,7 +736,8 @@ // release master lock spin_unlock_bh(&master->internal_lock); - queue_delayed_work(master->workqueue, &master->freerun_work, 1); + if (master->mode == EC_MASTER_MODE_FREERUN) + queue_delayed_work(master->workqueue, &master->freerun_work, 1); } /*****************************************************************************/ @@ -741,11 +748,16 @@ */ void ec_sync_config(const ec_sync_t *sync, /**< sync manager */ + const ec_slave_t *slave, /**< EtherCAT slave */ uint8_t *data /**> configuration memory */ ) { + size_t sync_size; + + sync_size = ec_slave_calc_sync_size(slave, sync); + EC_WRITE_U16(data, sync->physical_start_address); - EC_WRITE_U16(data + 2, sync->size); + EC_WRITE_U16(data + 2, sync_size); EC_WRITE_U8 (data + 4, sync->control_byte); EC_WRITE_U8 (data + 5, 0x00); // status byte (read only) EC_WRITE_U16(data + 6, 0x0001); // enable @@ -777,11 +789,16 @@ */ void ec_fmmu_config(const ec_fmmu_t *fmmu, /**< FMMU */ + const ec_slave_t *slave, /**< EtherCAT slave */ uint8_t *data /**> configuration memory */ ) { + size_t sync_size; + + sync_size = ec_slave_calc_sync_size(slave, fmmu->sync); + EC_WRITE_U32(data, fmmu->logical_start_address); - EC_WRITE_U16(data + 4, fmmu->sync->size); + EC_WRITE_U16(data + 4, sync_size); // size of fmmu EC_WRITE_U8 (data + 6, 0x00); // logical start bit EC_WRITE_U8 (data + 7, 0x07); // logical end bit EC_WRITE_U16(data + 8, fmmu->sync->physical_start_address); @@ -825,6 +842,44 @@ /*****************************************************************************/ /** + Formats attribute data for SysFS write access. + \return number of bytes processed, or negative error code +*/ + +ssize_t ec_store_master_attribute(struct kobject *kobj, /**< slave's kobject */ + struct attribute *attr, /**< attribute */ + const char *buffer, /**< memory with data */ + size_t size /**< size of data to store */ + ) +{ + ec_master_t *master = container_of(kobj, ec_master_t, kobj); + + if (attr == &attr_eeprom_write_enable) { + if (!strcmp(buffer, "1\n")) { + master->eeprom_write_enable = 1; + EC_INFO("Slave EEPROM writing enabled.\n"); + return size; + } + else if (!strcmp(buffer, "0\n")) { + master->eeprom_write_enable = 0; + EC_INFO("Slave EEPROM writing disabled.\n"); + return size; + } + + EC_ERR("Invalid value for eeprom_write_enable!\n"); + + if (master->eeprom_write_enable) { + master->eeprom_write_enable = 0; + EC_INFO("Slave EEPROM writing disabled.\n"); + } + } + + return -EINVAL; +} + +/*****************************************************************************/ + +/** Starts Ethernet-over-EtherCAT processing for all EoE-capable slaves. */ @@ -1088,7 +1143,7 @@ if (ec_command_npwr(command, slave->station_address, 0x0800 + j * EC_SYNC_SIZE, EC_SYNC_SIZE)) return -1; - ec_sync_config(sync, command->data); + ec_sync_config(sync, slave, command->data); if (unlikely(ec_master_simple_io(master, command))) { EC_ERR("Setting sync manager %i failed on slave %i!\n", j, slave->ring_position); @@ -1166,7 +1221,7 @@ if (ec_command_npwr(command, slave->station_address, 0x0600 + j * EC_FMMU_SIZE, EC_FMMU_SIZE)) return -1; - ec_fmmu_config(fmmu, command->data); + ec_fmmu_config(fmmu, slave, command->data); if (unlikely(ec_master_simple_io(master, command))) { EC_ERR("Setting FMMU %i failed on slave %i!\n", j, slave->ring_position); diff -r 9d7453c16ade -r 4bbe090553f7 master/master.h --- a/master/master.h Mon May 29 09:54:18 2006 +0000 +++ b/master/master.h Mon Jun 26 15:04:06 2006 +0000 @@ -122,6 +122,8 @@ int (*request_cb)(void *); /**< lock request callback */ void (*release_cb)(void *); /**< lock release callback */ void *cb_data; /**< data parameter of locking callbacks */ + + uint8_t eeprom_write_enable; /**< allow write operations to EEPROMs */ }; /*****************************************************************************/ @@ -149,9 +151,9 @@ // misc. void ec_master_clear_slaves(ec_master_t *); -void ec_sync_config(const ec_sync_t *, uint8_t *); +void ec_sync_config(const ec_sync_t *, const ec_slave_t *, uint8_t *); void ec_eeprom_sync_config(const ec_eeprom_sync_t *, uint8_t *); -void ec_fmmu_config(const ec_fmmu_t *, uint8_t *); +void ec_fmmu_config(const ec_fmmu_t *, const ec_slave_t *, uint8_t *); void ec_master_output_stats(ec_master_t *); /*****************************************************************************/ diff -r 9d7453c16ade -r 4bbe090553f7 master/slave.c --- a/master/slave.c Mon May 29 09:54:18 2006 +0000 +++ b/master/slave.c Mon Jun 26 15:04:06 2006 +0000 @@ -69,6 +69,7 @@ EC_SYSFS_READ_ATTR(sii_name); EC_SYSFS_READ_ATTR(type); EC_SYSFS_READ_WRITE_ATTR(state); +EC_SYSFS_READ_WRITE_ATTR(eeprom); static struct attribute *def_attrs[] = { &attr_ring_position, @@ -79,6 +80,7 @@ &attr_sii_name, &attr_type, &attr_state, + &attr_eeprom, NULL, }; @@ -145,6 +147,8 @@ slave->type = NULL; slave->registered = 0; slave->fmmu_count = 0; + slave->eeprom_data = NULL; + slave->eeprom_size = 0; slave->eeprom_group = NULL; slave->eeprom_image = NULL; slave->eeprom_order = NULL; @@ -153,13 +157,14 @@ slave->current_state = EC_SLAVE_STATE_UNKNOWN; slave->state_error = 0; slave->online = 1; - - ec_command_init(&slave->mbox_command); + slave->new_eeprom_data = NULL; + slave->new_eeprom_size = 0; INIT_LIST_HEAD(&slave->eeprom_strings); INIT_LIST_HEAD(&slave->eeprom_syncs); INIT_LIST_HEAD(&slave->eeprom_pdos); INIT_LIST_HEAD(&slave->sdo_dictionary); + INIT_LIST_HEAD(&slave->varsize_fields); for (i = 0; i < 4; i++) { slave->dl_link[i] = 0; @@ -186,6 +191,7 @@ ec_eeprom_pdo_entry_t *entry, *next_ent; ec_sdo_t *sdo, *next_sdo; ec_sdo_entry_t *en, *next_en; + ec_varsize_t *var, *next_var; slave = container_of(kobj, ec_slave_t, kobj); @@ -234,7 +240,14 @@ kfree(sdo); } - ec_command_clear(&slave->mbox_command); + // free information about variable sized data fields + list_for_each_entry_safe(var, next_var, &slave->varsize_fields, list) { + list_del(&var->list); + kfree(var); + } + + if (slave->eeprom_data) kfree(slave->eeprom_data); + if (slave->new_eeprom_data) kfree(slave->new_eeprom_data); } /*****************************************************************************/ @@ -1121,6 +1134,8 @@ EC_INFO(" EEPROM data:\n"); + EC_INFO(" EEPROM content size: %i Bytes\n", slave->eeprom_size); + if (slave->sii_alias) EC_INFO(" Configured station alias: 0x%04X (%i)\n", slave->sii_alias, slave->sii_alias); @@ -1239,6 +1254,83 @@ /*****************************************************************************/ /** + Schedules an EEPROM write operation. + \return 0 in case of success, else < 0 +*/ + +ssize_t ec_slave_write_eeprom(ec_slave_t *slave, /**< EtherCAT slave */ + const uint8_t *data, /**< new EEPROM data */ + size_t size /**< size of data in bytes */ + ) +{ + uint16_t word_size, cat_type, cat_size; + const uint16_t *data_words, *next_header; + uint16_t *new_data; + + if (!slave->master->eeprom_write_enable) { + EC_ERR("Writing EEPROMs not allowed! Enable via" + " eeprom_write_enable SysFS entry.\n"); + return -1; + } + + if (slave->master->mode != EC_MASTER_MODE_FREERUN) { + EC_ERR("Writing EEPROMs only allowed in freerun mode!\n"); + return -1; + } + + if (slave->new_eeprom_data) { + EC_ERR("Slave %i already has a pending EEPROM write operation!\n", + slave->ring_position); + return -1; + } + + // coarse check of the data + + if (size % 2) { + EC_ERR("EEPROM size is odd! Dropping.\n"); + return -1; + } + + data_words = (const uint16_t *) data; + word_size = size / 2; + + if (word_size < 0x0041) { + EC_ERR("EEPROM data too short! Dropping.\n"); + return -1; + } + + next_header = data_words + 0x0040; + cat_type = EC_READ_U16(next_header); + while (cat_type != 0xFFFF) { + cat_type = EC_READ_U16(next_header); + cat_size = EC_READ_U16(next_header + 1); + if ((next_header + cat_size + 2) - data_words >= word_size) { + EC_ERR("EEPROM data seems to be corrupted! Dropping.\n"); + return -1; + } + next_header += cat_size + 2; + cat_type = EC_READ_U16(next_header); + } + + // data ok! + + if (!(new_data = (uint16_t *) kmalloc(word_size * 2, GFP_KERNEL))) { + EC_ERR("Unable to allocate memory for new EEPROM data!\n"); + return -1; + } + memcpy(new_data, data, size); + + slave->new_eeprom_size = word_size; + slave->new_eeprom_data = new_data; + + EC_INFO("EEPROM writing scheduled for slave %i, %i words.\n", + slave->ring_position, word_size); + return 0; +} + +/*****************************************************************************/ + +/** Formats attribute data for SysFS read access. \return number of bytes to read */ @@ -1295,6 +1387,19 @@ return sprintf(buffer, "UNKNOWN\n"); } } + else if (attr == &attr_eeprom) { + if (slave->eeprom_data) { + if (slave->eeprom_size > PAGE_SIZE) { + EC_ERR("EEPROM contents of slave %i exceed 1 page (%i/%i).\n", + slave->ring_position, slave->eeprom_size, + (int) PAGE_SIZE); + } + else { + memcpy(buffer, slave->eeprom_data, slave->eeprom_size); + return slave->eeprom_size; + } + } + } return 0; } @@ -1338,10 +1443,51 @@ EC_ERR("Failed to set slave state!\n"); } + else if (attr == &attr_eeprom) { + if (!ec_slave_write_eeprom(slave, buffer, size)) + return size; + } return -EINVAL; } +/*****************************************************************************/ + +/** + \return size of sync manager contents +*/ + +size_t ec_slave_calc_sync_size(const ec_slave_t *slave, /**< EtherCAT slave */ + const ec_sync_t *sync /**< sync manager */ + ) +{ + unsigned int i, found; + const ec_field_t *field; + const ec_varsize_t *var; + size_t size; + + // if size is specified, return size + if (sync->size) return sync->size; + + // sync manager has variable size (size == 0). + + size = 0; + for (i = 0; (field = sync->fields[i]); i++) { + found = 0; + list_for_each_entry(var, &slave->varsize_fields, list) { + if (var->field != field) continue; + size += var->size; + found = 1; + } + + if (!found) { + EC_WARN("Variable data field \"%s\" of slave %i has no size" + " information!\n", field->name, slave->ring_position); + } + } + return size; +} + /****************************************************************************** * Realtime interface *****************************************************************************/ @@ -1361,9 +1507,75 @@ /*****************************************************************************/ +/** + \return 0 in case of success, else < 0 + \ingroup RealtimeInterface +*/ + +int ecrt_slave_field_size(ec_slave_t *slave, /**< EtherCAT slave */ + const char *field_name, /**< data field name */ + unsigned int field_index, /**< data field index */ + size_t size /**< new data field size */ + ) +{ + unsigned int i, j, field_counter; + const ec_sync_t *sync; + const ec_field_t *field; + ec_varsize_t *var; + + if (!slave->type) { + EC_ERR("Slave %i has no type information!\n", slave->ring_position); + return -1; + } + + field_counter = 0; + for (i = 0; (sync = slave->type->sync_managers[i]); i++) { + for (j = 0; (field = sync->fields[j]); j++) { + if (!strcmp(field->name, field_name)) { + if (field_counter++ == field_index) { + // is the size of this field variable? + if (field->size) { + EC_ERR("Field \"%s\"[%i] of slave %i has no variable" + " size!\n", field->name, field_index, + slave->ring_position); + return -1; + } + // does a size specification already exist? + list_for_each_entry(var, &slave->varsize_fields, list) { + if (var->field == field) { + EC_WARN("Resizing field \"%s\"[%i] of slave %i.\n", + field->name, field_index, + slave->ring_position); + var->size = size; + return 0; + } + } + // create a new size specification... + if (!(var = kmalloc(sizeof(ec_varsize_t), GFP_KERNEL))) { + EC_ERR("Failed to allocate memory for varsize_t!\n"); + return -1; + } + var->field = field; + var->size = size; + list_add_tail(&var->list, &slave->varsize_fields); + return 0; + } + } + } + } + + EC_ERR("Slave %i (\"%s %s\") has no field \"%s\"[%i]!\n", + slave->ring_position, slave->type->vendor_name, + slave->type->product_name, field_name, field_index); + return -1; +} + +/*****************************************************************************/ + /**< \cond */ EXPORT_SYMBOL(ecrt_slave_write_alias); +EXPORT_SYMBOL(ecrt_slave_field_size); /**< \endcond */ diff -r 9d7453c16ade -r 4bbe090553f7 master/slave.h --- a/master/slave.h Mon May 29 09:54:18 2006 +0000 +++ b/master/slave.h Mon Jun 26 15:04:06 2006 +0000 @@ -214,6 +214,20 @@ /*****************************************************************************/ /** + Variable-sized field information. +*/ + +typedef struct +{ + struct list_head list; /**< list item */ + const ec_field_t *field; /**< data field */ + size_t size; /**< field size */ +} +ec_varsize_t; + +/*****************************************************************************/ + +/** EtherCAT slave. */ @@ -261,23 +275,28 @@ ec_fmmu_t fmmus[EC_MAX_FMMUS]; /**< FMMU configurations */ uint8_t fmmu_count; /**< number of FMMUs used */ + uint8_t *eeprom_data; /**< Complete EEPROM image */ + uint16_t eeprom_size; /**< size of the EEPROM contents in byte */ struct list_head eeprom_strings; /**< EEPROM STRING categories */ struct list_head eeprom_syncs; /**< EEPROM SYNC MANAGER categories */ struct list_head eeprom_pdos; /**< EEPROM [RT]XPDO categories */ - char *eeprom_group; /**< slave group acc. to EEPROM */ char *eeprom_image; /**< slave image name acc. to EEPROM */ char *eeprom_order; /**< slave order number acc. to EEPROM */ char *eeprom_name; /**< slave name acc. to EEPROM */ + uint16_t *new_eeprom_data; /**< new EEPROM data to write */ + size_t new_eeprom_size; /**< size of new EEPROM data in words */ + struct list_head sdo_dictionary; /**< SDO directory list */ - ec_command_t mbox_command; /**< mailbox command */ - ec_slave_state_t requested_state; /**< requested slave state */ ec_slave_state_t current_state; /**< current slave state */ unsigned int state_error; /**< a state error has happened */ unsigned int online; /**< non-zero, if the slave responds. */ + + struct list_head varsize_fields; /**< size information for variable-sized + data fields. */ }; /*****************************************************************************/ @@ -306,6 +325,7 @@ int ec_slave_locate_string(ec_slave_t *, unsigned int, char **); // misc. +size_t ec_slave_calc_sync_size(const ec_slave_t *, const ec_sync_t *); void ec_slave_print(const ec_slave_t *, unsigned int); int ec_slave_check_crc(ec_slave_t *); diff -r 9d7453c16ade -r 4bbe090553f7 master/types.c --- a/master/types.c Mon May 29 09:54:18 2006 +0000 +++ b/master/types.c Mon Jun 26 15:04:06 2006 +0000 @@ -67,9 +67,39 @@ /*****************************************************************************/ +const ec_field_t bk1120_out = {"Outputs", 0}; // variable size +const ec_field_t bk1120_in = {"Inputs", 0}; // variable size + +const ec_sync_t bk1120_sm0 = {0x1C00, 264, 0x26, {NULL}}; +const ec_sync_t bk1120_sm1 = {0x1E00, 264, 0x22, {NULL}}; + +const ec_sync_t bk1120_sm2 = { // outputs + 0x1000, 0, 0x24, // variable size + {&bk1120_out, NULL} +}; + +const ec_sync_t bk1120_sm3 = { // inputs + 0x1600, 0, 0x00, // variable size + {&bk1120_in, NULL} +}; + const ec_slave_type_t Beckhoff_BK1120 = { "Beckhoff", "BK1120", "KBUS Coupler", EC_TYPE_NORMAL, - {NULL} // no sync managers + {&bk1120_sm0, &bk1120_sm1, &bk1120_sm2, &bk1120_sm3, NULL} +}; + +/*****************************************************************************/ + +const ec_field_t el1004_in = {"InputValue", 1}; + +const ec_sync_t el1004_sm0 = { // inputs + 0x1000, 1, 0x00, + {&el1004_in, NULL} +}; + +const ec_slave_type_t Beckhoff_EL1004 = { + "Beckhoff", "EL1004", "4x Digital Input, 3ms", EC_TYPE_NORMAL, + {&el1004_sm0, NULL} }; /*****************************************************************************/ @@ -82,7 +112,7 @@ }; const ec_slave_type_t Beckhoff_EL1014 = { - "Beckhoff", "EL1014", "4x Digital Input", EC_TYPE_NORMAL, + "Beckhoff", "EL1014", "4x Digital Input, 10us", EC_TYPE_NORMAL, {&el1014_sm0, NULL} }; @@ -186,8 +216,7 @@ {&el5101_st, &el5101_ip, &el5101_la, NULL} }; -const ec_slave_type_t Beckhoff_EL5101 = -{ +const ec_slave_type_t Beckhoff_EL5101 = { "Beckhoff", "EL5101", "Incremental Encoder Interface", EC_TYPE_NORMAL, {&mailbox_sm0, &mailbox_sm1, &el5101_sm2, &el5101_sm3, NULL} }; @@ -230,10 +259,11 @@ */ ec_slave_ident_t slave_idents[] = { + {0x00000002, 0x03EC3052, &Beckhoff_EL1004}, {0x00000002, 0x03F63052, &Beckhoff_EL1014}, {0x00000002, 0x044C2C52, &Beckhoff_EK1100}, {0x00000002, 0x04562C52, &Beckhoff_EK1110}, - //{0x00000002, 0x04602C22, &Beckhoff_BK1120}, + {0x00000002, 0x04602C22, &Beckhoff_BK1120}, {0x00000002, 0x07D43052, &Beckhoff_EL2004}, {0x00000002, 0x07F03052, &Beckhoff_EL2032}, {0x00000002, 0x0C1E3052, &Beckhoff_EL3102}, diff -r 9d7453c16ade -r 4bbe090553f7 script/ethercat.sh --- a/script/ethercat.sh Mon May 29 09:54:18 2006 +0000 +++ b/script/ethercat.sh Mon Jun 26 15:04:06 2006 +0000 @@ -66,14 +66,14 @@ start) echo -n "Starting EtherCAT master " - if [ ! $DEVICE_INDEX ]; then + if [ -z "$DEVICE_INDEX" ]; then echo "ERROR: DEVICE_INDEX not set!" /bin/false rc_status -v rc_exit fi - if [ ! $EOE_DEVICES ]; then + if [ -z "$EOE_DEVICES" ]; then EOE_DEVICES=0 fi @@ -99,6 +99,50 @@ rc_exit fi + # Build EoE bridge + if [ -n "$EOE_BRIDGE" ]; then + + EOE_INTERFACES=`/sbin/ifconfig -a | grep -o -E "^eoe[0-9]+ "` + + # add bridge, if it does not already exist + if ! /sbin/brctl show | grep -E -q "^$EOE_BRIDGE"; then + if ! /sbin/brctl addbr $EOE_BRIDGE; then + /bin/false + rc_status -v + rc_exit + fi + fi + + # free all interfaces of their addresses and add them to the bridge + for interface in $EOE_INTERFACES $EOE_EXTRA_INTERFACES; do + if ! /sbin/ifconfig $interface 0.0.0.0 up; then + /bin/false + rc_status -v + rc_exit + fi + if ! /sbin/brctl show | grep -E -q "^$EOE_BRIDGE.*$interface"; then + if ! /sbin/brctl addif $EOE_BRIDGE $interface; then + /bin/false + rc_status -v + rc_exit + fi + fi + done + if [ -n "$EOE_IP_ADDRESS" -a -n "$EOE_IP_NETMASK" ]; then + if ! /sbin/ifconfig $EOE_BRIDGE $EOE_IP_ADDRESS \ + netmask $EOE_IP_NETMASK; then + /bin/false + rc_status -v + rc_exit + fi + fi + if ! /sbin/ifconfig $EOE_BRIDGE up; then + /bin/false + rc_status -v + rc_exit + fi + fi + rc_status -v ;; diff -r 9d7453c16ade -r 4bbe090553f7 script/install.sh --- a/script/install.sh Mon May 29 09:54:18 2006 +0000 +++ b/script/install.sh Mon Jun 26 15:04:06 2006 +0000 @@ -49,24 +49,11 @@ exit 1 fi -#------------------------------------------------------------------------------ - -# Copy files - -INSTALLDIR=/lib/modules/$KERNEL/kernel/drivers/net -MODULES=(master/ec_master.ko devices/ec_8139too.ko) - echo "EtherCAT installer - Kernel: $KERNEL" -echo " Installing modules" - -for mod in ${MODULES[*]}; do - echo " $mod" - cp $mod $INSTALLDIR || exit 1 -done #------------------------------------------------------------------------------ -# Update dependencies +# Update module dependencies echo " Building module dependencies" depmod diff -r 9d7453c16ade -r 4bbe090553f7 script/sysconfig --- a/script/sysconfig Mon May 29 09:54:18 2006 +0000 +++ b/script/sysconfig Mon Jun 26 15:04:06 2006 +0000 @@ -18,4 +18,34 @@ # #EOE_DEVICES=0 +# +# Bridge all EoE interfaces after master startup +# This variable shall contain the name of the EoE bridge to set up. +# If the variable is empty or undefined, no EoE bridge will be built. +# +#EOE_BRIDGE=eoebr0 + +# +# IP address of the EoE bridge +# Set both EOE_IP_ADDRESS and EOE_IP_NETMASK to let the local host communicate +# with devices on the EoE bridge. +# +#EOE_IP_ADDRESS=192.168.X.X + +# +# IP netmask of the EoE bridge +# See EOE_IP_ADDRESS. +# +#EOE_IP_NETMASK=255.255.255.0 + +# +# List of extra interfaces to include in the EoE bridge. +# Set this to interconnect the EoE bridge with other local interfaces. +# If EOE_BRIDGE is empty or undefined, setting this variable has no effect. +# Important: The IP address of these interfaces will be cleared. Set +# EOE_IP_ADDRESS and EOE_IP_NETMASK accordingly to enable IP traffic to +# extra interfaces. +# +#EOE_EXTRA_INTERFACES=eth0 + #------------------------------------------------------------------------------