summaryrefslogtreecommitdiff
path: root/cleopatre
diff options
context:
space:
mode:
authorsave2008-12-18 10:06:35 +0000
committersave2008-12-18 10:06:35 +0000
commit1369b123d1b9afa9a5ddc70840684da3e451043e (patch)
tree6394a4b4027ab5175de1161169bd232da646ee69 /cleopatre
parent527d65fbeba78df8a05e12aa3171138d4055d2d1 (diff)
[CLEO][PLCDRV]uppest layer of the plcdrv with fisrt step of the utests
git-svn-id: svn+ssh://pessac/svn/cesar/trunk@3688 017c9cb6-072f-447c-8318-d5b54f68fe89
Diffstat (limited to 'cleopatre')
-rw-r--r--cleopatre/common/make/utests_makerules46
-rw-r--r--cleopatre/plcdrv/arm/inc/common.h14
-rw-r--r--cleopatre/plcdrv/arm/inc/linux_drv.h74
-rw-r--r--cleopatre/plcdrv/arm/inc/plc_drv.h42
-rw-r--r--cleopatre/plcdrv/arm/src/linux_drv.c649
-rw-r--r--cleopatre/plcdrv/arm/src/plc_drv.c448
-rw-r--r--cleopatre/plcdrv/arm/utests/Makefile6
-rw-r--r--cleopatre/plcdrv/arm/utests/inc/linux_drv_utests.h247
-rw-r--r--cleopatre/plcdrv/arm/utests/src/linux_drv_utests.c94
9 files changed, 1125 insertions, 495 deletions
diff --git a/cleopatre/common/make/utests_makerules b/cleopatre/common/make/utests_makerules
new file mode 100644
index 0000000000..6a8cd15032
--- /dev/null
+++ b/cleopatre/common/make/utests_makerules
@@ -0,0 +1,46 @@
+TEST_NAME = utests
+
+PRJ_SRCPATH = ../src
+TEST_SRCPATH = src
+PRJ_INCPATH = ../inc
+TEST_INCPATH = ./inc
+
+OBJPATH = obj
+PRJ_OBJPATH = $(OBJPATH)/prj
+TEST_OBJPATH = $(OBJPATH)/test
+
+BINS = $(foreach file, $(FILES), $(OBJPATH)/$(file).elf)
+
+
+CC = gcc
+CFLAGS = -Wall -O -g -D__UTESTS__ -I$(PRJ_INCPATH) -I$(TEST_INCPATH)
+LDFLAGS =
+LIBS = -lcheck
+
+all: preall $(BINS)
+
+clean:
+ rm -f $(OBJPATH)/*.elf
+ rm -f $(PRJ_OBJPATH)/*.o $(TEST_OBJPATH)/*.o $(OBJPATH)/*.o
+ rmdir $(TEST_OBJPATH)
+ rmdir $(PRJ_OBJPATH)
+ rmdir $(OBJPATH)
+
+preall:
+ mkdir -p $(OBJPATH)
+ mkdir -p $(PRJ_OBJPATH)
+ mkdir -p $(TEST_OBJPATH)
+
+.PHONY: all clean
+.PRECIOUS: $(PRJ_OBJPATH)/%.o $(TEST_OBJPATH)/%.o
+
+$(OBJPATH)/%.elf: $(PRJ_OBJPATH)/%.o $(TEST_OBJPATH)/%_$(TEST_NAME).o
+ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+
+$(TEST_OBJPATH)/%.o: $(TEST_SRCPATH)/%.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(PRJ_OBJPATH)/%.o: $(PRJ_SRCPATH)/%.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
diff --git a/cleopatre/plcdrv/arm/inc/common.h b/cleopatre/plcdrv/arm/inc/common.h
index d76c6dc57b..e21f78d63c 100644
--- a/cleopatre/plcdrv/arm/inc/common.h
+++ b/cleopatre/plcdrv/arm/inc/common.h
@@ -1,6 +1,6 @@
#ifndef common_h
#define common_h
-/* Cesar project {{{
+/* Cleopatre project {{{
*
* Copyright (C) 2008 Spidcom
*
@@ -9,13 +9,17 @@
* }}} */
/**
* \file common.h
- * \brief « brief description »
- * \ingroup Cleopatre - Isis
+ * \brief general definitions
+ * \ingroup Cleopatre - PlcDrv
*
- * « long description »
+ * This file content all definitions needed by all different layers
*/
-/** type of buffer */
+/** Max size of an Ethernet frame (size for all buffers) must be align on 4 bytes */
+#define PKT_BUF_SZ 1524
+
+
+/** Type of buffer */
enum buffer_type {
DATA = 0,
MME = 1,
diff --git a/cleopatre/plcdrv/arm/inc/linux_drv.h b/cleopatre/plcdrv/arm/inc/linux_drv.h
new file mode 100644
index 0000000000..53ebb74fb5
--- /dev/null
+++ b/cleopatre/plcdrv/arm/inc/linux_drv.h
@@ -0,0 +1,74 @@
+#ifndef linux_drv_h
+#define linux_drv_h
+/* Cleopatre project {{{
+ *
+ * Copyright (C) 2008 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file linux_drv.h
+ * \brief interfaces for linux_drv layer
+ * \ingroup Cleopatre - PlcDrv
+ *
+ * this file content interfaces and exported macros, variables... For the
+ * linux_drv layer
+ */
+
+#include "common.h"
+
+#ifdef __UTESTS__
+#include "linux_drv_utests.h"
+#endif
+
+/** why do you want to free the buffer */
+enum free_reason {
+ RX_DROP = 0,
+ TX_DROP = 1,
+ TX_COMPLETE = 2,
+};
+
+/**
+ * Receive a packet.
+ * \param packet packet pointer.
+ * \param length packet length.
+ * \return error code.
+ */
+int plcdrv_rx(void *packet, int length);
+
+/**
+ * Release a buffer.
+ * \param packet packet pointer.
+ * \param reason freeing reason.
+ * \return error code.
+ */
+int free_buffer(void *packet, enum free_reason reason);
+
+/**
+ * Alloc a buffer and send to the communication layer.
+ * \param type type of buffer to allocate.
+ * \return error code.
+ */
+int alloc_buffer(enum buffer_type type);
+
+/**
+ * Changed a virtual address to its corresponding physical address
+ * and manage the cache.
+ * \param addr buffer virtual address.
+ * \param len buffer length.
+ * \return buffer physical address.
+ */
+uint32_t prepare_buffer_to_hw(uint32_t addr, unsigned int len);
+
+/**
+ * Changed a physical address to its corresponding virtual address
+ * and manage the cache.
+ * \param addr buffer physical address.
+ * \param len buffer length.
+ * \return buffer virtual address.
+ */
+uint32_t prepare_buffer_from_hw(uint32_t addr, unsigned int len);
+
+#endif /* linux_drv_h */
+
diff --git a/cleopatre/plcdrv/arm/inc/plc_drv.h b/cleopatre/plcdrv/arm/inc/plc_drv.h
deleted file mode 100644
index c6a389bac4..0000000000
--- a/cleopatre/plcdrv/arm/inc/plc_drv.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef plc_drv_h
-#define plc_drv_h
-/* Cesar project {{{
- *
- * Copyright (C) 2008 Spidcom
- *
- * <<<Licence>>>
- *
- * }}} */
-/**
- * \file plc_drv.h
- * \brief « brief description »
- * \ingroup Cleopatre - Isis
- *
- * « long description »
- */
-
-#include "common.h"
-
-/** why do you want to free the buffer */
-enum free_reason {
- RX_DROP = 0,
- TX_DROP = 1,
- TX_COMPLETE = 2,
-};
-
-/**
- * Receive a packet
- */
-int plcdrv_rx (void *pointer, int length);
-
-/**
- * Release a sk_buff
- */
-int free_buffer (void *pointer, enum free_reason reason);
-
-/**
- * Alloc sk_buff and send to the communication layer
- */
-int alloc_buffer (enum buffer_type type);
-
-#endif /* plc_drv_h */
diff --git a/cleopatre/plcdrv/arm/src/linux_drv.c b/cleopatre/plcdrv/arm/src/linux_drv.c
new file mode 100644
index 0000000000..13c4283ad1
--- /dev/null
+++ b/cleopatre/plcdrv/arm/src/linux_drv.c
@@ -0,0 +1,649 @@
+/* Cleopatre project {{{
+ *
+ * Copyright (C) 2008 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file linux_drv.c
+ * \brief Linux Driver layer
+ * \ingroup Cleopatre - PlcDrv
+ *
+ * This file content the Linux Driver layer, this layer correspond to the
+ * interface between the driver and Linux (it's a network Linux driver).
+ */
+
+
+#define DRV_NAME "SPC300"
+#define DRV_VERSION "1.0"
+//#define DRV_RELDATE "Dec 05, 2008"
+#define DRV_RELDATE __DATE__
+
+
+#ifndef __UTESTS__
+#include <linux/kernel.h>
+#include <linux/module.h>
+//#include <linux/version.h>
+#include <linux/init.h>
+//#include <linux/errno.h>
+#include <linux/netdevice.h>
+//#include <linux/etherdevice.h>
+//#include <asm/arch/hardware.h>
+//#include <asm/io.h>
+//#include <linux/proc_fs.h>
+//#include <linux/sysctl.h>
+//#include <asm/cacheflush.h>
+//#include <linux/ethtool.h>
+//#include <linux/mii.h>
+//#include <linux/dma-mapping.h>
+//#include <linux/kthread.h>
+
+#include "common.h"
+#include "linux_drv.h"
+#include "processing.h"
+#else
+#include "common.h"
+#include "linux_drv.h"
+#endif
+
+
+MODULE_AUTHOR("SPiDCOM Technologies");
+MODULE_DESCRIPTION("SPC300 PLC driver");
+MODULE_LICENSE("SPiDCOM Technologies 2009");
+
+/** Define Debug/Trace Level */
+#define TRACE(...) printk(DRV_NAME": " __VA_ARGS__)
+//#define TRACE(...)
+
+/** Define default rings size */
+#define DEFAULT_NB_DATA_BUFFERS 5
+#define DEFAULT_NB_MME_BUFFERS 5
+#define DEFAULT_NB_INTERFACE_BUFFERS 5
+
+/** These identify the driver base version */
+static char version[] __devinitdata = DRV_NAME " PLC driver v" DRV_VERSION " (" DRV_RELDATE ")\n";
+
+/** Driver Private datas */
+struct net_priv {
+ uint32_t num_mbx_it;
+ uint32_t num_mbx_it_ack;
+ struct net_device_stats stats;
+};
+
+/** Our global net device */
+static struct net_device *plcdrv_device;
+
+/** Parameters for the module */
+static int rx_data_skb_ring_size = DEFAULT_NB_DATA_BUFFERS;
+static int rx_mme_skb_ring_size = DEFAULT_NB_MME_BUFFERS;
+static int rx_interface_skb_ring_size = DEFAULT_NB_INTERFACE_BUFFERS;
+module_param(rx_data_skb_ring_size, int, 0644);
+MODULE_PARM_DESC(rx_data_skb_ring_size, "Number of Data Ethernet buffers for PLC -> ARM exchanges");
+module_param(rx_mme_skb_ring_size, int, 0644);
+MODULE_PARM_DESC(rx_mme_skb_ring_size, "Number of MME Ethernet buffers for PLC -> ARM exchanges");
+module_param(rx_interface_skb_ring_size, int, 0644);
+MODULE_PARM_DESC(rx_mme_skb_ring_size, "Number of Interface Ethernet buffers for PLC -> ARM exchanges");
+
+/**
+ * Find with sk_buff data field address the sk_buff structure address.
+ * \param skbdata_addr the sk_buff data field address.
+ * \return sk_buff address.
+ */
+static inline uint32_t get_skb_addr(uint32_t skbdata_addr)
+{
+ struct sk_buff *skb = NULL;
+ return (skbdata_addr - ((uint32_t)(&skb->data)));
+}// get_skb_addr
+
+/**
+ * Changed a virtual address to its corresponding physical address
+ * and manage the cache.
+ * \param addr buffer virtual address.
+ * \param len buffer length.
+ * \return buffer physical address.
+ */
+uint32_t prepare_buffer_to_hw(uint32_t addr, unsigned int len)
+{
+ //Invalidate cached areas
+ dma_cache_maint((const void*)addr, len, DMA_BIDIRECTIONAL);
+
+ //Find the corresponding physical addr
+ return (uint32_t)(virt_to_dma(NULL, addr));
+}// prepare_buffer_to_hw
+
+/**
+ * Changed a physical address to its corresponding virtual address
+ * and manage the cache.
+ * \param addr buffer physical address.
+ * \param len buffer length.
+ * \return buffer virtual address.
+ */
+uint32_t prepare_buffer_from_hw(uint32_t addr, unsigned int len)
+{
+ //Invalidate cached areas
+ dma_cache_maint((const void*)addr, len, DMA_BIDIRECTIONAL);
+
+ //Find the corresponding virtual addr
+ return (uint32_t)(dma_to_virt(NULL, addr));
+}// prepare_buffer_from_hw
+
+/**
+ * Alloc a buffer to the pool
+ * and send to the communication layer.
+ * \param type type of buffer to allocate.
+ * \return error code.
+ */
+int alloc_buffer(enum buffer_type type)
+{
+ struct sk_buff *skb;
+ uint32_t pointer;
+ int result;
+
+ //Allocate an sk_buff
+ skb = alloc_skb(PKT_BUF_SZ, GFP_KERNEL | GFP_DMA);
+ if(!skb)
+ {
+ printk(KERN_ERR DRV_NAME": Error allocating RX buffers for %s\n",dev->name);
+ return -ENOMEM;
+ }
+
+ //Find the physical addr of the data part and map it
+ pointer = (uint32_t)dma_map_single(NULL, skb->data, skb->len, DMA_FROM_DEVICE);
+
+ //Send this allocated pointer to lower layer
+ if((result = mailbox_buffer_add((void*)pointer, type)))
+ {
+ kfree_skb(skb);
+ return result;
+ }
+ return 0;
+}// alloc_buffer
+
+/**
+ * Release a buffer from the pool.
+ * \param packet packet pointer.
+ * \param reason freeing reason.
+ * \return error code.
+ */
+int free_buffer(void *packet, enum free_reason reason)
+{
+ struct net_priv *priv = (struct net_priv*)plcdrv_device->priv;
+ struct sk_buff *skb;
+ uint32_t virt_pkt_addr;
+
+ if(packet)
+ {
+ //Find the corresponding virtual addr
+ virt_pkt_addr = dma_to_virt(NULL, (uint32_t)packet);
+
+ //Find the sk_buff associated to this packet
+ skb = (struct sk_buff*)get_skb_addr(virt_pkt_addr);
+
+ //Check the free reason for stats
+ switch(reason)
+ {
+ case RX_DROP: priv->stats.rx_dropped++;
+ break;
+ case TX_DROP: priv->stats.tx_dropped++;
+ break;
+ case TX_COMPLETE: priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+ break;
+ }
+
+ //Unmap the sk_buff
+ dma_unmap_single(NULL, (uint32_t)skb->data, skb->len, DMA_FROM_DEVICE);
+
+ //Free sk_buff
+ kfree_skb(skb);
+ return 0;
+ }
+ else
+ {
+ printk(KERN_ERR DRV_NAME": %s: error freeing a NULL buffer\n", dev->name);
+ return -1;
+ }
+}// free_buffer
+
+/**
+ * Receive a packet.
+ * \param packet packet pointer.
+ * \param length packet length.
+ * \return error code.
+ */
+int plcdrv_rx(void *packet, int length)
+{
+ struct net_priv *priv = (struct net_priv*)plcdrv_device->priv;
+ struct sk_buff *skb;
+ int result;
+
+ TRACE("%s: Receive\n", dev->name);
+
+ if(packet)
+ {
+
+ //Find the sk_buff address
+ skb = (struct sk_buff *)get_skb_addr((uint32_t)packet);
+
+ //Pass data to the linux internal receive level
+ skb->dev = plcdrv_device;
+ skb->protocol = eth_type_trans(skb, plcdrv_device);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += length;
+ netif_rx(skb);
+ result = 0;
+ }
+ else
+ {
+ printk(KERN_ERR DRV_NAME": %s: Error Receiving a NULL buffer\n", dev->name);
+ result = -1;
+ }
+
+ TRACE("%s: Receive done\n", dev->name);
+ return result;
+}// plcdrv_rx
+
+/**
+ * Transmit frame procedure.
+ * \param skb frame structure.
+ * \param dev device structure.
+ * \return error code.
+ */
+int plcdrv_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_priv *priv = (struct net_priv*)plcdrv_device->priv;
+ int status;
+
+ TRACE("%s: Transmit\n", dev->name);
+
+ //Send buffer to lower layers
+ status = processing_send((void *)skb->data, skb->len);
+ if(status == NEARLY_FULL)
+ {
+ netif_stop_queue(dev);
+ }
+ else if(status == FULL)
+ {
+ netif_stop_queue(dev);
+ priv->stats.tx_fifo_errors++;
+ kfree_skb(skb);
+ }
+
+ //Handle transmit
+ dev->trans_start = jiffies;
+
+ TRACE("%s: Transmit end\n", dev->name);
+
+ return 0;
+}// plcdrv_tx
+
+/**
+ * Interrupt Handler Receive procedure.
+ * \param irq interrupt number.
+ * \param dev device structure.
+ * \return error code.
+ */
+irqreturn_t plcdrv_it_rx(int irq, void * dev_id)
+{
+ struct net_device *dev = (struct net_device*)dev_id;
+ int result;
+
+ TRACE("%s: Receive\n", dev->name);
+
+ //Just call the lowest layer procedure
+ if(mailbox_receive())
+ result = IRQ_NONE;
+ else
+ result = IRQ_HANDLED;
+ TRACE("%s: Receive end\n", dev->name);
+
+ return result;
+}// plcdrv_it_rx
+
+/**
+ * Finish the transmit frame procedure.
+ * \param irq interrupt number.
+ * \param dev device structure.
+ */
+irqreturn_t plcdrv_it_txdone(int irq, void * dev_id)
+{
+ struct net_device *dev = (struct net_device*)dev_id;
+
+ TRACE("%s: Transmit Done\n", dev->name);
+ if(netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+ TRACE("%s: Transmit Done end\n", dev->name);
+
+ return IRQ_HANDLED;
+}// plcdrv_it_txdone
+
+/**
+ * Read packet status from the device.
+ * \param dev device structure.
+ * \return the device stats.
+ */
+struct net_device_stats *plcdrv_stats(struct net_device *dev)
+{
+ struct net_priv *priv = NULL;
+
+ //Check pointers
+ if(dev == NULL)
+ return NULL;
+
+ priv = (struct net_priv *)dev->priv;
+ if(priv == NULL)
+ return NULL;
+
+ return &priv->stats;
+}// plcdrv_stats
+
+/**
+ * Change the MTU.
+ * \param dev device structure.
+ * \param new_mtu the new mtu value.
+ * \return error code.
+ */
+int plcdrv_change_mtu(struct net_device *dev, int new_mtu)
+{
+ //Check pointers
+ if(dev == NULL)
+ return -1;
+
+ //Check arguments
+ if(new_mtu < 64 || new_mtu > 1508)
+ return -EINVAL;
+ else
+ {
+ dev->mtu = new_mtu;
+ return 0;
+ }
+}// plcdrv_change_mtu
+
+/**
+ * Change the MAC address.
+ * \param dev device structure.
+ * \param p mac addr source.
+ * \return error code.
+ */
+int plcdrv_set_mac_address(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+
+ //Check pointers
+ if(dev == NULL)
+ return -1;
+ if(p == NULL)
+ return -1;
+
+ TRACE("%s: set_mac_address\n", dev->name);
+
+ //Store the new address for Linux
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ //TODO:Store the new address in NVRAM
+
+ TRACE("%s: set_mac_address end\n", dev->name);
+
+ return 0;
+}// plcdrv_set_mac_address
+
+/**
+ * User control device interface.
+ * \param dev device structure.
+ * \param ifr user exchange structure.
+ * \param cmd command to execute.
+ * \return error code.
+ */
+int plcdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ //Check pointers
+ if(ifr == NULL)
+ return -1;
+ if(dev == NULL)
+ return -1;
+
+ TRACE("%s: ioctl\n", dev->name);
+
+ //Find the command
+ switch(cmd)
+ {
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ TRACE("%s: ioctl end\n", dev->name);
+
+ return 0;
+}// plcdrv_ioctl
+
+/**
+ * Initialize the device.
+ * \param dev device structure.
+ * \return error code.
+ */
+int plcdrv_open(struct net_device *dev)
+{
+ struct net_priv *priv = NULL;
+ int i;
+
+ //Check pointers
+ if(dev == NULL)
+ return -1;
+ priv = (struct net_priv *)dev->priv;
+ if(priv == NULL)
+ return -1;
+
+ TRACE("%s: open\n", dev->name);
+
+ //Start lower Layers
+ processing_init();
+
+ //Allocate RX buffer pool to give to CESAR
+ for(i=0 ; i<rx_data_skb_ring_size ; i++)
+ {
+ if(alloc_buffer(DATA))
+ {
+ printk(KERN_ERR DRV_NAME ": %s: error creating DATA buffer pool\n", dev->name);
+ return -ENOMEM;
+ }
+ }
+ for(i=0 ; i<rx_mme_skb_ring_size ; i++)
+ {
+ if(alloc_buffer(MME))
+ {
+ printk(KERN_ERR DRV_NAME ": %s: error creating MME buffer pool\n", dev->name);
+ return -ENOMEM;
+ }
+ }
+ for(i=0 ; i<rx_interface_skb_ring_size ; i++)
+ {
+ if(alloc_buffer(INTERFACE))
+ {
+ printk(KERN_ERR DRV_NAME ": %s: error creating INTERFACE buffer pool\n", dev->name);
+ return -ENOMEM;
+ }
+ }
+
+ //Prepare Linux as link up
+ netif_carrier_on(dev);
+ netif_start_queue(dev);
+
+ //Request Receive IRQ
+ if(request_irq(priv->num_mbx_it, plcdrv_it_rx, 0, dev->name, dev) != 0)
+ {
+ printk(KERN_ERR DRV_NAME ": %s - interrupt %d request fail\n", dev->name, dev->irq);
+ return -ENODEV;
+ }
+
+ //Request Transmit Acknowledge IRQ
+ if(request_irq(priv->num_mbx_it_ack, plcdrv_it_txdone, 0, dev->name, dev) != 0)
+ {
+ printk(KERN_ERR DRV_NAME ": %s - interrupt %d request fail\n", dev->name, dev->irq);
+ return -ENODEV;
+ }
+
+ TRACE("%s: open end\n", dev->name);
+
+ return 0;
+}// plcdrv_open
+
+/**
+ * Uninitialize the device.
+ * \param dev device structure.
+ * \return error code.
+ */
+int plcdrv_stop(struct net_device *dev)
+{
+ struct net_priv *priv = NULL;
+
+ //Check pointers
+ if(dev == NULL)
+ return -1;
+ priv = (struct net_priv *)dev->priv;
+ if(priv == NULL)
+ return -1;
+
+ TRACE("%s: stop\n", dev->name);
+
+ //Disable transmitter
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+
+ //Stop lower layers
+ processing_uninit();
+
+ //Disconnect from IRQ
+ free_irq(priv->num_mbx_it, dev);
+ free_irq(priv->num_mbx_it_ack, dev);
+
+ //TODO:Freeing all buffers
+ //TODO: send a message to processing layer or communication layer
+ //that we want to shutdown le plc driver
+ //Wait all allocated sk_buff become free
+ //(a sk_buff become free when we receive a send_done procedure)
+
+ TRACE("%s: stop end\n", dev->name);
+
+ return 0;
+}// plcdrv_stop
+
+/**
+ * Initialise the network device.
+ * \param dev device structure.
+ * \return error code.
+ */
+int plcdrv_init(struct net_device *dev)
+{
+ struct net_priv *priv = NULL;
+
+ //Check pointers
+ if(dev == NULL)
+ return -1;
+ priv = (struct net_priv *)dev->priv;
+ if(priv == NULL)
+ return -1;
+
+ TRACE("%s: init\n", dev->name);
+
+ //Set IP base addresses
+ dev->base_addr = (unsigned int)ioremap(MBX_BASE_ADDR, 6);
+
+ //Set Interrupts numbers
+ dev->irq = INT_MBX; //do not use dev->irq because there more than one IT given by the hardware
+ priv->num_mbx_it = INT_MBX;
+ priv->num_mbx_it_ack = INT_MBX_ACK;
+
+ //TODO:May be Attach hardware layer addresses + start leon....
+
+ //Initialise device functions
+ ether_setup(dev);
+ dev->open = plcdrv_open;
+ dev->stop = plcdrv_stop;
+ dev->do_ioctl = plcdrv_ioctl;
+ dev->set_mac_address = plcdrv_set_mac_address;
+ dev->hard_start_xmit = plcdrv_tx;
+ dev->get_stats = plcdrv_stats;
+/* dev->tx_timeout = plcdrv_tx_timeout; */
+/* dev->watchdog_timeo = TX_TIMEOUT; */
+ dev->change_mtu = plcdrv_change_mtu;
+
+ //TODO:Setup MAC address for Linux (stored in NVRAM)
+ dev->dev_addr[0] = 0x00;
+ dev->dev_addr[1] = 0x11;
+ dev->dev_addr[2] = 0x22;
+ dev->dev_addr[3] = 0x33;
+ dev->dev_addr[4] = 0x44;
+ dev->dev_addr[5] = 0x55;
+
+ TRACE("%s: init end\n", dev->name);
+
+ return 0;
+}// plcdrv_init
+
+/**
+ * Initialise the module.
+ * \return error code.
+ */
+int __init plcdrv_module_init(void)
+{
+ int result;
+ struct net_device *dev;
+
+ printk("%s", version);
+
+ //Allocate device memory
+ dev = alloc_netdev(sizeof(struct net_priv), "plc%d", ether_setup);
+ if((dev == NULL) || (dev->priv == NULL))
+ result = -ENOMEM;
+
+ //Proceed the init driver
+ dev->init = plcdrv_init;
+
+ //Register net device
+ result = register_netdev(dev);
+ if(result < 0)
+ {
+ printk(KERN_ERR DRV_NAME": Error %i registering %s\n", result, dev->name);
+ kfree(dev->priv);
+ free_netdev(dev);
+ }
+ else
+ {
+ plcdrv_device = dev;
+ }
+
+ return result;
+}// plcdrv_module_init
+
+/**
+ * Uninitialise the module.
+ */
+void __exit plcdrv_module_exit(void)
+{
+ struct net_priv *priv;
+
+ if(plcdrv_device)
+ {
+ //Unmap IP address
+ if(plcdrv_device->base_addr)
+ iounmap((void*)plcdrv_device->base_addr);
+
+ //Freeing private field of the net device structure
+ priv = plcdrv_device->priv;
+ if(priv)
+ kfree(priv);
+
+ //Unregister net device
+ unregister_netdev(plcdrv_device);
+
+ //Freeing network device
+ free_netdev(plcdrv_device);
+ }
+
+}// plcdrv_module_exit
+
+module_init(plcdrv_init_module);
+module_exit(plcdrv_exit_module);
+
diff --git a/cleopatre/plcdrv/arm/src/plc_drv.c b/cleopatre/plcdrv/arm/src/plc_drv.c
deleted file mode 100644
index 7bd3cbe302..0000000000
--- a/cleopatre/plcdrv/arm/src/plc_drv.c
+++ /dev/null
@@ -1,448 +0,0 @@
-/* Cesar project {{{
- *
- * Copyright (C) 2008 Spidcom
- *
- * <<<Licence>>>
- *
- * }}} */
-/**
- * \file plc_drv.c
- * \brief « brief description »
- * \ingroup Cleopatre - Isis
- *
- * « long description »
- */
-
-
-#define DRV_NAME "SPC200AV"
-#define DRV_VERSION "1.0"
-#define DRV_RELDATE "Mar 18, 2008"
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-//#include <linux/version.h>
-#include <linux/init.h>
-//#include <linux/errno.h>
-#include <linux/netdevice.h>
-//#include <linux/etherdevice.h>
-//#include <asm/arch/hardware.h>
-//#include <asm/io.h>
-//#include <linux/proc_fs.h>
-//#include <linux/sysctl.h>
-//#include <asm/cacheflush.h>
-//#include <linux/ethtool.h>
-//#include <linux/mii.h>
-//#include <linux/dma-mapping.h>
-//#include <linux/kthread.h>
-
-#include "common.h"
-#include "plc_drv.h"
-#include "processing.h"
-#include "mailbox.h"
-
-MODULE_AUTHOR("SPiDCOM Technologies");
-MODULE_DESCRIPTION("SPC200AV PLC driver");
-MODULE_LICENSE("SPiDCOM Technologies 2008");
-
-/** Define declarations */
-#define PKT_BUF_SZ 1522 //Size of each ethernet frame allocation
-#define SKB_RESERVE (2+32) //align IP Header
-
-#define DATA_TYPE 0
-#define MME_TYPE 1
-
-//These identify the driver base version and may not be removed
-static char version[] __devinitdata = DRV_NAME " PLC driver v" DRV_VERSION " (" DRV_RELDATE ")\n";
-
-/** Driver Private datas */
-typedef struct {
- uint32_t nb_skbs_in_use;
- struct net_device_stats stats;
-} Private;
-
-/** Global data declaration */
-static struct net_device *plcdrv_dev;
-
-/** Parameters for the module */
-//TODO:put the 50 into a define
-static int rx_data_skb_ring_size = 50;
-static int rx_mme_skb_ring_size = 50;
-module_param(rx_data_skb_ring_size, int, 0644);
-MODULE_PARM_DESC(rx_data_skb_ring_size, "Number of data Ethernet buffers for PLC-> ARM echanges");
-module_param(rx_mme_skb_ring_size, int, 0644);
-MODULE_PARM_DESC(rx_mme_skb_ring_size, "Number of MME Ethernet buffers for PLC-> ARM echanges");
-
-/**
- * find offset of the data field in a sk_buff structure
- *
- * \return offset
- */
-static inline int get_skb_data_offset()
-{
- struct sk_buff skb;
- return (int)(&skb - &skb.data);
-}
-
-/**
- * Previous sending message to the HLE layer is ok (IT ALA)
- *
- * \param int_num interrupt number.
- * \param dev_id device address.
- * \return error code
- */
-static irqreturn_t tx_ack (int int_num, void *dev_id, struct pt_regs *regs)
-{
- struct net_device *dev = (struct net_device *)dev_id;
- if(netif_queue_stopped(dev))
- netif_wake_queue(dev);
-}//tx_ack
-
-/**
- * Receive a message from the HLE (after IT LAT)
- *
- * \param int_num interrupt number.
- * \param dev_id device address.
- * \return error code
- */
-static irqreturn_t rx_handler (int int_num, void *dev_id, struct pt_regs *regs)
-{
- mailbox_receive();
- return IRQ_HANDLED;
-}//rx_handler
-
-/**
- * Receive a packet
- *
- * \param pointer buffer pointer.
- * \param length length of the message pointed.
- * \return error code
- */
-int plcdrv_rx (void *pointer, int length)
-{
- Private *pr = (Private*)plcdrv_dev->priv;
- struct sk_buff skb;
- int offset;
-
- if(pointer)
- {
- offset = get_skb_data_offset();
-
- //Find the sk_buff address
- skb = (struct sk_buff *)(pointer - offset);
-
- //Pass data to the linux internal receive level
- skb->dev = plcdrv_dev;
- skb->protocol = eth_type_trans(skb, plcdrv_dev);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += length;
- netif_rx(skb);
- return 0;
- }
- else
- {
- printk(KERN_ERR DRV_NAME": %s: error freeing a NULL buffer\n", dev->name);
- return -1;
- }
-}//plcdrv_rx
-
-/**
- * Transmit a packet
- *
- * \param skb packet structure address.
- * \param dev device address.
- * \return error code
- */
-static int plcdrv_tx (struct sk_buff *skb, struct net_device *dev)
-{
- Private *pr = (Private*)dev->priv;
- int status;
-
- //Handle transmit
- dev->trans_start = jiffies;
-
- //Send buffer to lower layers
- status = processing_send((void *)skb->data, skb->len);
- if(status == NEARLY_FULL)
- {
- netif_stop_queue(dev);
- }
- else if(status == FULL)
- {
- netif_stop_queue(dev);
- pr->stats.tx_qfull_err++;
- dev_kfree_skb(skb);
- }
- return 0;
-}//plcdrv_tx
-
-/**
- * Read packet status from the device
- *
- * \param dev device address.
- * \return device stats
- */
-static struct net_device_stats *plcdrv_get_stats (struct net_device *dev)
-{
- Private *pr = NULL;
-
- if(dev == NULL)
- return NULL;
- pr = (Private *)dev->priv;
- if(pr == NULL)
- return NULL;
-
- return &pr->stats;
-}//plcdrv_get_stats
-
-/**
- * Release a sk_buff
- *
- * \param pointer buffer pointer.
- * \param reason reason to release the buffer
- * \return error code
- */
-int free_buffer(void *pointer, enum free_reason reason)
-{
- Private *pr = (Private*)plcdrv_dev->priv;
- struct sk_buff *skb;
- int offset;
-
- if(pointer)
- {
- //Find the sk_buff address
- offset = get_skb_data_offset();
- skb = (struct sk_buff *)(pointer - offset);
-
- //Check the free reason for stats
- switch(reason)
- {
- case RX_DROP: pr->stats.rx_dropped++;
- break;
- case TX_DROP: pr->stats.tx_dropped++;
- break;
- case TX_COMPLETE: pr->stats.tx_packets++;
- pr->stats.tx_bytes += skb->len;
- break;
- }
-
- //Free sk_buff
- dev_free_skb(skb);
- pr->nb_skbs_in_use--;
- return 0;
- }
- else
- {
- printk(KERN_ERR DRV_NAME": %s: error freeing a NULL buffer\n", dev->name);
- return -1;
- }
-}//free_buffer
-
-/**
- * Alloc sk_buff and send to the communication layer
- *
- * \param type type of buffer.
- * \return error code
- */
-int alloc_buffer(enum buffer_type type)
-{
- int result = 0;
- Private *pr = (Private*)plcdrv_dev->priv;
- struct sk_buff *skb;
-
- //Alloc a new sk_buff
- skb = dev_alloc_skb(PKT_BUF_SZ+SKB_RESERVE, GFP_KERNEL);
- if(!skb)
- {
- printk(KERN_ERR DRV_NAME": %s: error allocating sk_buff for\n",plcdrv_dev->name);
- return -ENOMEM;
- }
- skb_reserve(skb, SKB_RESERVE); //To ensure IP header is 4byte aligned after 14byte Eth header
-
- //Send the buffer to the communication layer
- if(result = mailbox_buffer_add((void*)skb->data), type)
- {
- dev_free_skb(skb);
- return result;
- }
- pr->nb_skbs_in_use++;
- return 0;
-}//alloc_buffer
-
-/**
- * Initialize the device
- *
- * \param dev device address.
- * \return error code
- */
-static int plcdrv_open (struct net_device *dev)
-{
- Private *pr = (Private*)dev->priv;
- int i;
-
- //Initialize lower layers
- processing_init();
-
- //Set number of sk_buff in use
- pr->nb_skbs_in_use = 0;
-
- //Alloc skbuff pool for data rx packet
- for(i=0 ; i<rx_data_skb_ring_size ; i++)
- {
- if(alloc_buffer(DATA))
- {
- printk(KERN_ERR DRV_NAME ": %s: error creating data buffer pool\n", dev->name);
- return -ENOMEM;
- }
- }
- //Alloc skbuff pool for mme rx packet
- for(i=0 ; i<rx_mme_skb_ring_size ; i++)
- {
- if(alloc_buffer(MME))
- {
- printk(KERN_ERR DRV_NAME ": %s: error creating mme buffer pool\n", dev->name);
- return -ENOMEM;
- }
- }
- //Alloc skbuff pool for interface rx packet
- for(i=0 ; i<rx_mme_skb_ring_size ; i++)
- {
- if(alloc_buffer(INTERFACE))
- {
- printk(KERN_ERR DRV_NAME ": %s: error creating interface buffer pool\n", dev->name);
- return -ENOMEM;
- }
- }
-
- //Start transmit
- netif_start_queue(dev);
- return 0;
-}//plcdrv_open
-
-/**
- * Stop the device
- *
- * \param dev device address.
- * \return error code
- */
-static int plcdrv_close (struct net_device *dev)
-{
- Private *pr = (Private*)dev->priv;
-
- //TODO: send a message to processing layer or communication layer
- //that we want to shutdown le plc driver
-
- //Wait all allocated sk_buff become free
- //(a sk_buff become free when we receive a send_done procedure)
- while(pr->nb_skbs_in_use);
-
- //Uninitialize lower layers
- processing_uninit();
- return 0;
-}//plcdrv_close
-
-/**
- * Initialize the module
- *
- * \param dev device address.
- * \return error code
- */
-static int plcdrv_init (struct net_device *dev)
-{
- int result = 0;
- Private *pr = NULL;
-
- if(dev == NULL)
- return -ENODEV;
-
- pr = (Private *)dev->priv;
-
- //Initialisation functions
-//TODO:check if without it's ok ether_setup (dev);
-//TODO dev->tx_queue_len = 1000;
- dev->open = &plcdrv_open;
- dev->hard_start_xmit = &plcdrv_tx;
- dev->stop = &plcdrv_close;
- dev->get_stats = &plcdrv_get_stats;
- dev->weight = 32;
-
- //mask mailbox interrupts
- lat_it_disable();
- ala_it_disable();
-
- //Register these interrupts
- result = request_irq(LAT_IT_NUM, rx_handler, SA_INTERRUPT, "RX Mailbox msg", 0); //LAT interrupt
- result = request_irq(ALA_IT_NUM, tx_ack, SA_INTERRUPT, "TX Ack msg", dev); //ALA interrupt
-
- return result;
-}//plcdrv_init
-
-/**
- * Register the module
- *
- * \return error code
- */
-static int plcdrv_init_module (void)
-{
- int result;
- Private *pr;
- struct net_device *dev;
-
- printk("%s", version);
-
- //Alloc memory for netdevice private structure
- dev = alloc_netdev(sizeof(Private), "plc%d", ether_setup);
- if((NULL == dev) || NULL == dev->priv)
- {
- result = -ENOMEM;
- }
- pr = (Private*)dev->priv;
-
- //Store init function
- dev->init = plcdrv_init;
- SET_MODULE_OWNER(dev);
-
- //Register net device
- result = register_netdev(dev);
- if(result < 0)
- {
- printk(KERN_ERR DRV_NAME ": plc0: Could not register device\n");
- kfree(pr);
- free_netdev(dev);
- }
- else
- {
- plcdrv_dev = dev;
- }
- return result;
-}//plcdrv_init_module
-
-/**
- * Release the module
- */
-static void plcdrv_exit_module (void)
-{
- Private *pr = plcdrv_dev->priv;
-
- if(plcdrv_dev)
- {
- //Freeing private field of the net device struture
- if(pr)
- kfree(pr);
-
- //Freeing interrupts
- free_irq(LAT_IT_NUM, plcdrv_dev);
- free_irq(ALA_IT_NUM, plcdrv_dev);
- //Freeing network device
- free_netdev(plcdrv_dev);
-
- //Unregister net device
- unregister_netdev(plcdrv_dev);
- }
-
-}//plcdrv_exit_module
-
-module_init(plcdrv_init_module);
-module_exit(plcdrv_exit_module);
-
diff --git a/cleopatre/plcdrv/arm/utests/Makefile b/cleopatre/plcdrv/arm/utests/Makefile
new file mode 100644
index 0000000000..008e84ffae
--- /dev/null
+++ b/cleopatre/plcdrv/arm/utests/Makefile
@@ -0,0 +1,6 @@
+FILES = linux_drv
+#FILES += processing
+#FILES += mailbox
+#FILES += hal
+
+include ../../../common/make/utests_makerules
diff --git a/cleopatre/plcdrv/arm/utests/inc/linux_drv_utests.h b/cleopatre/plcdrv/arm/utests/inc/linux_drv_utests.h
new file mode 100644
index 0000000000..f5b76ded6b
--- /dev/null
+++ b/cleopatre/plcdrv/arm/utests/inc/linux_drv_utests.h
@@ -0,0 +1,247 @@
+#ifndef linux_drv_utests_h
+#define linux_drv_utests_h
+/* Cleopatre project {{{
+ *
+ * Copyright (C) 2008 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file linux_drv_utests.h
+ * \brief interfaces for unitary tests of linux_drv layer
+ * \ingroup Cleopatre - PlcDrv
+ *
+ * this file content interfaces and exported macros, variables... For the
+ * unitary tests of linux_drv layer
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+/****************************************************/
+/***** SPECIFIC STUB *****/
+/****************************************************/
+#define MBX_BASE_ADDR 0x1234567
+#define INT_MBX 12
+#define INT_MBX_ACK 13
+static inline void processing_init(void){}
+static inline void processing_uninit(void){}
+static inline int processing_send(void *pointer, int length){return 0;}
+#define NOT_FULL 0
+#define FULL -1
+#define NEARLY_FULL -2
+static inline int mailbox_buffer_add(void *pointer, enum buffer_type type){return 0;}
+static inline int mailbox_receive(void){return 0;}
+
+/****************************************************/
+/***** LINUX STUB *****/
+/****************************************************/
+#define kfree free
+#define printk(...)
+#define irqreturn_t int
+#define jiffies 1234
+#define IRQ_HANDLED 1
+#define IRQ_NONE 0
+#define EOPNOTSUPP 1
+#define EINVAL 1
+#define ENODEV 1
+#define ENOMEM 1
+#define KERN_ERR
+#define __init
+#define __exit
+#define __devinitdata
+#define MODULE_AUTHOR(a)
+#define MODULE_DESCRIPTION(a)
+#define MODULE_LICENSE(a)
+#define MODULE_PARM_DESC(a,b)
+#define module_param(a,b,c)
+#define module_init(a)
+#define module_exit(a)
+#define DMA_BIDIRECTIONAL 1
+#define GFP_KERNEL 1
+#define GFP_DMA 1
+#define DMA_FROM_DEVICE 1
+#define DMA_TO_DEVICE 1
+#define CHECKSUM_UNNECESSARY 1
+
+typedef irqreturn_t (*irq_handler_t)(int, void *);
+
+struct sk_buff {
+ unsigned char *data;
+ struct net_device *dev;
+ unsigned int len;
+ unsigned short protocol;
+ unsigned char ip_summed;
+};
+struct net_device_stats {
+ unsigned long rx_packets;
+ unsigned long tx_packets;
+ unsigned long rx_bytes;
+ unsigned long tx_bytes;
+ unsigned long rx_dropped;
+ unsigned long tx_dropped;
+ unsigned long tx_fifo_errors;
+};
+struct ifreq {
+ char dummy;
+};
+struct sockaddr {
+ char sa_data[14];
+};
+struct net_device {
+ char name[16];
+ unsigned long base_addr;
+ void *priv;
+ unsigned char dev_addr[32];
+ unsigned char addr_len;
+ unsigned int irq;
+ unsigned int mtu;
+ unsigned long trans_start;
+ int (*init)(struct net_device *dev);
+ int (*hard_start_xmit)(struct sk_buff *skb, struct net_device *dev);
+ int (*open)(struct net_device *dev);
+ int (*stop)(struct net_device *dev);
+ int (*set_mac_address)(struct net_device *dev, void *addr);
+ struct net_device_stats* (*get_stats)(struct net_device *dev);
+ int (*do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
+ int (*change_mtu)(struct net_device *dev, int new_mtu);
+};
+
+static inline void *ioremap(unsigned long phys_addr, unsigned int size){return (void*)phys_addr;}
+static inline void iounmap(void* addr){}
+static inline void ether_setup(struct net_device *dev){}
+static inline unsigned short eth_type_trans(struct sk_buff *skb, struct net_device *dev){return 5;}
+static inline void netif_carrier_on(struct net_device *dev){}
+static inline void netif_start_queue(struct net_device *dev){}
+static inline void netif_carrier_off(struct net_device *dev){}
+static inline void netif_stop_queue(struct net_device *dev){}
+static inline void netif_wake_queue(struct net_device *dev){}
+static inline int netif_rx(struct sk_buff *skb){return 0;}
+static inline int netif_queue_stopped(const struct net_device *dev){return 0;}
+static inline int register_netdev(struct net_device *dev){return 0;}
+static inline void unregister_netdev(struct net_device *dev){}
+static inline int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id){return 0;}
+static inline void free_irq(unsigned int irq, void *dev_id){}
+static inline void dma_cache_maint(const void *start, unsigned int size, int direction){}
+static inline unsigned int virt_to_dma(void* dev, unsigned int addr){return addr;}
+static inline unsigned int dma_to_virt(void* dev, unsigned int addr){return addr;}
+static inline unsigned int dma_map_single(void *dev, void *ptr, unsigned int size, int dir){return (unsigned int)ptr;}
+static inline void dma_unmap_single(void *dev, unsigned int dma_addr, unsigned int size, int dir){}
+static inline struct sk_buff *alloc_skb(unsigned int size, int priority)
+{
+ struct sk_buff* skb;
+ skb = (struct sk_buff*)malloc((unsigned int)(sizeof(struct sk_buff)));
+ return skb;
+}
+static inline void kfree_skb(struct sk_buff *skb)
+{
+ if(skb)
+ free(skb);
+}
+static inline struct net_device *alloc_netdev(int sizeof_priv, const char *name, void (*setup)(struct net_device *))
+{
+ struct net_device* dev;
+ dev = (struct net_device*)malloc((unsigned int)(sizeof(struct net_device)));
+ dev->priv = malloc((unsigned int)(sizeof_priv));
+ return dev;
+}
+static inline void free_netdev(struct net_device* dev)
+{
+ if(dev->priv)
+ free(dev->priv);
+ free((void*)(dev));
+}
+
+/****************************************************/
+/***** STATIC FUNCTION PROTOTYPES *****/
+/****************************************************/
+/**
+ * Receive frame procedure.
+ * \param irq interrupt number.
+ * \param dev device structure.
+ * \return error code.
+ */
+irqreturn_t plcdrv_it_rx(int irq, void * dev_id);
+
+/**
+ * Finish the transmit frame procedure.
+ * \param irq interrupt number.
+ * \param dev device structure.
+ */
+irqreturn_t plcdrv_it_txdone(int irq, void * dev_id);
+
+/**
+ * Transmit frame procedure.
+ * \param skb frame structure.
+ * \param dev device structure.
+ * \return error code.
+ */
+int plcdrv_tx(struct sk_buff *skb, struct net_device *dev);
+
+/**
+ * Read packet status from the device.
+ * \param dev device structure.
+ * \return the device stats.
+ */
+struct net_device_stats *plcdrv_stats(struct net_device *dev);
+
+/**
+ * Change the MTU.
+ * \param dev device structure.
+ * \param new_mtu the new mtu value.
+ * \return error code.
+ */
+int plcdrv_change_mtu(struct net_device *dev, int new_mtu);
+
+/**
+ * Change the MAC address.
+ * \param dev device structure.
+ * \param p mac addr source.
+ * \return error code.
+ */
+int plcdrv_set_mac_address(struct net_device *dev, void *p);
+
+/**
+ * User control device interface.
+ * \param dev device structure.
+ * \param ifr user exchange structure.
+ * \param cmd command to execute.
+ * \return error code.
+ */
+int plcdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+
+/**
+ * Initialize the device.
+ * \param dev device structure.
+ * \return error code.
+ */
+int plcdrv_open(struct net_device *dev);
+
+/**
+ * Uninitialize the device.
+ * \param dev device structure.
+ * \return error code.
+ */
+int plcdrv_stop(struct net_device *dev);
+
+/**
+ * Initialise the network device.
+ * \param dev device structure.
+ * \return error code.
+ */
+int plcdrv_init(struct net_device *dev);
+
+/**
+ * Initialise the module.
+ * \return error code.
+ */
+int __init plcdrv_module_init(void);
+
+/**
+ * Uninitialise the module.
+ */
+void __exit plcdrv_module_exit(void);
+
+#endif /* linux_drv_utests_h */
diff --git a/cleopatre/plcdrv/arm/utests/src/linux_drv_utests.c b/cleopatre/plcdrv/arm/utests/src/linux_drv_utests.c
new file mode 100644
index 0000000000..ec341b9d35
--- /dev/null
+++ b/cleopatre/plcdrv/arm/utests/src/linux_drv_utests.c
@@ -0,0 +1,94 @@
+/* Cleopatre project {{{
+ *
+ * Copyright (C) 2008 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file linux_drv_utests.c
+ * \brief Unitary tests for Linux Driver layer
+ * \ingroup Cleopatre - PlcDrv
+ *
+ * This file content all the unitary tests for the Linux Driver layer,
+ * this layer correspond to the interface between
+ * the driver and Linux (it's a network Linux driver).
+ */
+
+#include <check.h>
+#include <stdio.h>
+#include <string.h>
+#include "linux_drv.h"
+
+/** local variables */
+static struct net_device dev;
+
+/** change mtu procedure */
+START_TEST (test_plc_drv_change_mtu)
+{
+ fail_if(plcdrv_change_mtu(NULL, 1234) != -1, "Error with arguments checking");
+ fail_if(plcdrv_change_mtu(&dev, 63) >= 0, "Error with too small mtu");
+ fail_if(plcdrv_change_mtu(&dev, 1510) >= 0, "Error with too big mtu");
+ fail_if(plcdrv_change_mtu(&dev, 1400) < 0, "Error with a correct mtu");
+}
+END_TEST
+
+/** set mac address procedure */
+START_TEST (test_plc_drv_set_mac_address)
+{
+ struct sockaddr addr;
+ int i;
+
+ fail_if(plcdrv_set_mac_address(NULL, NULL) != -1, "Error with first arguments checking");
+ fail_if(plcdrv_set_mac_address(&dev, NULL) != -1, "Error with second arguments checking");
+
+ for(i=0 ; i<sizeof(addr.sa_data) ; i++)
+ {
+ addr.sa_data[i] = i*11;
+ }
+
+ dev.addr_len = 0;
+ memset(dev.dev_addr, 0, sizeof(dev.dev_addr));
+ plcdrv_set_mac_address(&dev, &addr);
+ fail_if(memcmp(dev.dev_addr, addr.sa_data, dev.addr_len) != 0, "Error with mac address length=0");
+ dev.addr_len = 21;
+ memset(dev.dev_addr, 0, sizeof(dev.dev_addr));
+ plcdrv_set_mac_address(&dev, &addr);
+ fail_if(memcmp(dev.dev_addr, addr.sa_data, dev.addr_len) != 0, "Error with mac address length too big");
+ dev.addr_len = 6;
+ memset(dev.dev_addr, 0, sizeof(dev.dev_addr));
+ plcdrv_set_mac_address(&dev, &addr);
+ fail_if(memcmp(dev.dev_addr, addr.sa_data, dev.addr_len) != 0, "Error with mac address copy");
+}
+END_TEST
+
+extern Suite* plc_drv_suite(void)
+{
+ Suite *s = suite_create("PLC_DRV");
+ TCase *tc_core = tcase_create("Core");
+
+ //Test change mtu
+ tcase_add_test(tc_core, test_plc_drv_change_mtu);
+ //Test set mac address
+ tcase_add_test(tc_core, test_plc_drv_set_mac_address);
+
+ suite_add_tcase(s, tc_core);
+ return s;
+}
+
+int main(void)
+{
+ int number_failed = 0;
+ Suite *s;
+
+ //Run PLCDRV tests
+ s = plc_drv_suite();
+
+ SRunner *sr = srunner_create(s);
+ srunner_run_all(sr, CK_NORMAL);
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ return (number_failed == 0) ? 0 : -1;
+}
+