diff rathaxes_add_lkm_ethernet_sample.patch @ 38:f43900ad7e66

Fold All The Patches on the LKM Sample
author Louis Opter <louis@lse.epitech.net>
date Sun, 08 Jan 2012 01:51:34 +0100
parents rathaxes_add_a_linux_lkm.patch@44a25ffd5c8c
children d761c8c625d3
line wrap: on
line diff
--- a/rathaxes_add_lkm_ethernet_sample.patch	Sun Jan 08 01:45:20 2012 +0100
+++ b/rathaxes_add_lkm_ethernet_sample.patch	Sun Jan 08 01:51:34 2012 +0100
@@ -1,40 +1,120 @@
 # HG changeset patch
-# Parent a109185dcd773ae92b98a8195b7cc91f1c1cee47
+# Parent b995d8934956b83383c144303178f3eb383d0acf
 rathaxes: add the PCI/Ethernet part of a Linux Intel e1000 network card driver
 
+diff --git a/rathaxes/samples/CMakeLists.txt b/rathaxes/samples/CMakeLists.txt
+--- a/rathaxes/samples/CMakeLists.txt
++++ b/rathaxes/samples/CMakeLists.txt
+@@ -1,2 +1,3 @@
+ ADD_SUBDIRECTORY(helloworld)
++ADD_SUBDIRECTORY(lkm)
+ ADD_SUBDIRECTORY(syntax)
+diff --git a/rathaxes/samples/lkm/CMakeLists.txt b/rathaxes/samples/lkm/CMakeLists.txt
+new file mode 100644
+--- /dev/null
++++ b/rathaxes/samples/lkm/CMakeLists.txt
+@@ -0,0 +1,7 @@
++ADD_RATHAXES_SOURCES(lkm lkm.rtx
++                     RTI log.rti lkm.rti pci.rti socket.rti ethernet.rti e1000.rti
++                     BLT log.blt lkm.blt pci.blt socket.blt ethernet.blt e1000.blt)
++
++# We can't name lkm since it's already used as the target name to generate the
++# source (with ADD_RATHAXES_SOURCES).
++ADD_RATHAXES_LKM(lkm_hello lkm)
 diff --git a/rathaxes/samples/lkm/e1000.blt b/rathaxes/samples/lkm/e1000.blt
---- a/rathaxes/samples/lkm/e1000.blt
+new file mode 100644
+--- /dev/null
 +++ b/rathaxes/samples/lkm/e1000.blt
-@@ -5,7 +5,7 @@
-         chunk   LKM::includes()
-         {
-             /*
--             * Force the generation of the structure in the "headers part, we
+@@ -0,0 +1,80 @@
++with e1000, Ethernet, Socket, PCI, LKM, Log
++{
++    template type   e1000::Context()
++    {
++        chunk   LKM::includes()
++        {
++            /*
 +             * Force the generation of the structure in the "headers" part, we
-              * have to do this since we do not use the structure in this blt
-              * (we hacked a bit and used it in ethernet.blt directly).
-              */
-@@ -64,8 +64,10 @@
-     {
-         chunk   Ethernet::destroy_device
-         {
--            // XXX: add a check in order to avoid freeing none allocated
--            // resources.
++             * have to do this since we do not use the structure in this blt
++             * (we hacked a bit and used it in ethernet.blt directly).
++             */
++            typedef int ${e1000::Context}; /* CNorm __std__ workaround */
++            ${e1000::Context} force_declaration_in_includes;
++        }
++
++        chunk   ::decl()
++        {
++            struct rtx_e1000_ctx
++            {
++                int                             bars;
++                unsigned char /* __iomem */     *ioaddr;
++            };
++        }
++
++        map
++        {
++        }
++    }
++
++    template sequence   e1000::create_device()
++    {
++        chunk Ethernet::create_device()
++        {
++            rtx_ether_ctx->hw_ctx.bars = pci_select_bars(pdev, IORESOURCE_MEM);
++            if (pci_enable_device_mem(pdev))
++            {
++                ${Log::info("e1000::create: pci_enable_device_mem failed")};
++            }
++
++            if (pci_request_selected_regions(pdev, rtx_ether_ctx->hw_ctx.bars, ${config.name}))
++            {
++                ${Log::info("e1000::create: pci_request_selected_regions failed")};
++            }
++
++            if (${config.set_master})
++            {
++                pci_set_master(pdev);
++            }
++
++            /* 0 here is for BAR_0: */
++            rtx_ether_ctx->hw_ctx.ioaddr = pci_ioremap_bar(pdev, 0);
++            if (!rtx_ether_ctx->hw_ctx.ioaddr)
++            {
++                ${Log::info("e1000::create: pci_ioremap_bar failed")};
++            }
++        }
++
++        chunk ::CALL
++        {
++        }
++    }
++
++    template sequence   e1000::destroy_device()
++    {
++        chunk   Ethernet::destroy_device
++        {
 +            /*
 +             * Here, we should have some checks to avoid to free resources that
 +             * haven't been allocated. (e.g: in case of previous errors).
 +             */
-             struct rtx_ethernet_dev* rtx_ether_ctx = netdev_priv(net_dev);
-             iounmap(rtx_ether_ctx->hw_ctx.ioaddr);
-             pci_release_selected_regions(pdev, rtx_ether_ctx->hw_ctx.bars);
++            struct rtx_ethernet_dev* rtx_ether_ctx = netdev_priv(net_dev);
++            iounmap(rtx_ether_ctx->hw_ctx.ioaddr);
++            pci_release_selected_regions(pdev, rtx_ether_ctx->hw_ctx.bars);
++        }
++
++        chunk   ::CALL
++        {
++        }
++    }
++}
 diff --git a/rathaxes/samples/lkm/e1000.rti b/rathaxes/samples/lkm/e1000.rti
---- a/rathaxes/samples/lkm/e1000.rti
+new file mode 100644
+--- /dev/null
 +++ b/rathaxes/samples/lkm/e1000.rti
-@@ -2,7 +2,14 @@
- {
-     provided type   e1000::Context;
- 
--    /* Not sure if we need the argument */
+@@ -0,0 +1,24 @@
++interface e1000 : Socket, Ethernet, PCI, LKM
++{
++    provided type   e1000::Context;
++
 +    /*
 +     * This sequence should receive an argument like Ethernet::Device, but it is
 +     * unclear about how this argument should be bound to a variable/argument in
@@ -43,138 +123,561 @@
 +     * Here again, we rely on the fact that *we* wrote the parent context and
 +     * named the C variables we need/use with the same name everywhere.
 +     */
-     provided sequence   e1000::create_device()
-     {
-         provided chunk  Ethernet::create_device;
++    provided sequence   e1000::create_device()
++    {
++        provided chunk  Ethernet::create_device;
++        provided chunk  ::CALL;
++    }
++
++    provided sequence   e1000::destroy_device()
++    {
++        provided chunk  Ethernet::destroy_device;
++        provided chunk  ::CALL;
++    }
++}
 diff --git a/rathaxes/samples/lkm/ethernet.blt b/rathaxes/samples/lkm/ethernet.blt
---- a/rathaxes/samples/lkm/ethernet.blt
+new file mode 100644
+--- /dev/null
 +++ b/rathaxes/samples/lkm/ethernet.blt
-@@ -6,8 +6,6 @@
-         {
-             #include <linux/netdevice.h>
-             #include <linux/etherdevice.h>
--
--            typedef int include_linux_net_system_stamp;
-         }
- 
-         chunk ::decl()
-@@ -93,10 +91,9 @@
-     template sequence   Ethernet::interrupt_handler(Ethernet::Device dev)
-     {
-         /*
--         * Why we can't use irqreturn_t here? (we are forced to use enum
--         * irqreturn, which is the real type).
+@@ -0,0 +1,207 @@
++with Ethernet, PCI, LKM, Log
++{
++    template type   Ethernet::Device()
++    {
++        chunk LKM::includes()
++        {
++            #include <linux/netdevice.h>
++            #include <linux/etherdevice.h>
++        }
++
++        chunk ::decl()
++        {
++            struct rtx_ethernet_dev
++            {
++                /*
++                 * I think it's useless to use the ${PCI::Device} "abstraction"
++                 * here, since we are already in a Linux specific context here.
++                 */
++                struct pci_dev          *pci_dev;
++                struct net_device       *net_dev;
++
++                /* while waiting on issue #8 */
++                struct rtx_e1000_ctx    hw_ctx;
++            };
++        }
++
++        chunk ::init(net_dev)
++        {
++            ${self} = ${net_dev};
++        }
++
++        map
++        {
++        }
++    }
++
++    template sequence   Ethernet::open(Ethernet::Device dev)
++    {
++        chunk LKM::prototypes()
++        {
++            static int  rtx_ethernet_open(struct net_device *);
++        }
++
++        chunk LKM::code()
++        {
++            static int  rtx_ethernet_open(struct net_device *dev)
++            {
++                ${pointcut ::IMPLEMENTATION};
++
++                return 0;
++            }
++        }
++    }
++
++    template sequence   Ethernet::send(Ethernet::Device dev, Socket::SKBuff skb)
++    {
++        chunk LKM::prototypes()
++        {
++            static int  rtx_ethernet_xmit(struct sk_buff* skb, struct net_device *dev);
++        }
++
++        chunk LKM::code()
++        {
++            static int  rtx_ethernet_xmit(struct sk_buff* skb, struct net_device *dev)
++            {
++                ${pointcut ::IMPLEMENTATION};
++
++                return 0;
++            }
++        }
++    }
++
++    template sequence   Ethernet::close(Ethernet::Device dev)
++    {
++        chunk LKM::prototypes()
++        {
++            static int  rtx_ethernet_close(struct net_device *);
++        }
++
++        chunk LKM::code()
++        {
++            static int  rtx_ethernet_close(struct net_device *dev)
++            {
++                ${pointcut ::IMPLEMENTATION};
++
++                return 0;
++            }
++        }
++    }
++
++    template sequence   Ethernet::interrupt_handler(Ethernet::Device dev)
++    {
++        /*
 +         * We can't use the irqreturn_t type here because CNornm doesn't know
 +         * it.
-          */
--
-         chunk LKM::prototypes()
-         {
-             static enum irqreturn   rtx_ethernet_interrupt_handler(int, void *);
-@@ -141,7 +138,12 @@
-             if (net_dev == 0)
-             {
-                 ${Log::info("Cannot allocate memory")};
--                // is it the thing to do?
++         */
++        chunk LKM::prototypes()
++        {
++            static enum irqreturn   rtx_ethernet_interrupt_handler(int, void *);
++        }
++
++        chunk LKM::code()
++        {
++            static enum irqreturn   rtx_ethernet_interrupt_handler(int irq, void *dev_id)
++            {
++                ${pointcut ::IMPLEMENTATION};
++
++                return IRQ_NONE;
++            }
++        }
++    }
++
++    template sequence   Ethernet::init(PCI::Device pdev)
++    {
++        chunk LKM::data()
++        {
++            static const struct net_device_ops  rtx_ether_ops =
++            {
++                .ndo_open = rtx_ethernet_open,
++                .ndo_stop = rtx_ethernet_close,
++                .ndo_start_xmit = rtx_ethernet_xmit,
++            };
++        }
++
++        chunk PCI::pci_probe_hook()
++        {
++            /*
++             * This typedef is needed to workaround a bug in CNorm __std__
++             * dialect.
++             */
++            typedef int ${Ethernet::Device};
++            ${Ethernet::Device} *rtx_ether_ctx;
++            struct net_device   *net_dev;
++            int error;
++
++            error = 0;
++            net_dev = alloc_etherdev(sizeof(*rtx_ether_ctx));
++            if (net_dev == 0)
++            {
++                ${Log::info("Cannot allocate memory")};
 +                /*
 +                 * Again, the error should be "raised" in the parent context.
 +                 *
 +                 * Here we know that we should return ENOMEM because *we* wrote
 +                 * the parent context.
 +                 */
-                 return -ENOMEM;
-             }
-             strlcpy(net_dev->name, ${config.ifname}, sizeof(net_dev->name));
-@@ -166,13 +168,13 @@
-             if ((error = register_netdev(net_dev)))
-             {
-                 ${Log::info("Cannot register the driver")};
--                // is it the thing to do?
-                 return error;
-             }
- 
-             /* same problem as above with ${pdev} */
-             //pci_set_drvdata(${pdev}, net_dev);
-             pci_set_drvdata(pdev, net_dev);
++                return -ENOMEM;
++            }
++            strlcpy(net_dev->name, ${config.ifname}, sizeof(net_dev->name));
++            net_dev->irq = pdev->irq;
++            // Maybe we should try ${rtx_ether_ctx.init()} here:
++            rtx_ether_ctx = netdev_priv(net_dev);
++            //rtx_ether_ctx->pci_dev = ${pdev};
++            rtx_ether_ctx->pci_dev = pdev; // In the meantime do it directly
++            rtx_ether_ctx->net_dev = net_dev;
++
++            /*
++             * The substitution of ${pdev} fails here. I also tried to add a
++             * "substitute method" to the PCI::Device that was just doing
++             * "${self}" but it didn't work either (it was subsituted by a
++             * placeholder, e.g: _1).
++             *
++             * That's why we cheated a bit and named all the arguments pdev.
++             */
++            //SET_NETDEV_DEV(net_dev, &${pdev}->dev);
++            SET_NETDEV_DEV(net_dev, &pdev->dev);
++            net_dev->netdev_ops = &rtx_ether_ops;
++            if ((error = register_netdev(net_dev)))
++            {
++                ${Log::info("Cannot register the driver")};
++                return error;
++            }
++
++            /* same problem as above with ${pdev} */
++            //pci_set_drvdata(${pdev}, net_dev);
++            pci_set_drvdata(pdev, net_dev);
 +
-             ${pointcut Ethernet::create_device};
-         }
- 
++            ${pointcut Ethernet::create_device};
++        }
++
++        chunk   ::CALL
++        {
++        }
++    }
++
++    template sequence   Ethernet::exit(PCI::Device pdev)
++    {
++        chunk   PCI::pci_remove_hook()
++        {
++            struct net_device *net_dev = pci_get_drvdata(pdev);
++
++            ${pointcut Ethernet::destroy_device};
++
++            unregister_netdev(net_dev);
++            /*
++             * If we had some cleanup todo with struct rtx_ether_ctx we would
++             * do a netdev_priv(net_dev) here and do it.
++             */
++            free_netdev(net_dev);
++        }
++
++        chunk ::CALL
++        {
++        }
++    }
++}
++
 diff --git a/rathaxes/samples/lkm/ethernet.rti b/rathaxes/samples/lkm/ethernet.rti
---- a/rathaxes/samples/lkm/ethernet.rti
+new file mode 100644
+--- /dev/null
 +++ b/rathaxes/samples/lkm/ethernet.rti
-@@ -37,7 +37,6 @@
-         provided pointcut   Ethernet::create_device;
-     }
- 
--    /* Likely extends PCI::remove */
-     provided sequence   Ethernet::exit(PCI::Device)
-     {
-         provided chunk  ::CALL;
+@@ -0,0 +1,47 @@
++interface Ethernet : Socket, PCI, LKM
++{
++    provided type       Ethernet::Device;
++
++    required variable ::string  Ethernet::ifname;
++
++    required sequence   Ethernet::open(Ethernet::Device)
++    {
++        provided chunk  LKM::prototypes;
++        provided chunk  LKM::code;
++    }
++
++    required sequence   Ethernet::send(Ethernet::Device dev, Socket::SKBuff skb)
++    {
++        provided chunk  LKM::prototypes;
++        provided chunk  LKM::code;
++    }
++
++    required sequence   Ethernet::close(Ethernet::Device)
++    {
++        provided chunk  LKM::prototypes;
++        provided chunk  LKM::code;
++    }
++
++    required sequence   Ethernet::interrupt_handler(Ethernet::Device)
++    {
++        provided chunk  LKM::prototypes;
++        provided chunk  LKM::code;
++    }
++
++    provided sequence   Ethernet::init(PCI::Device)
++    {
++        provided chunk  LKM::data;
++        provided chunk  PCI::pci_probe_hook;
++        provided chunk  ::CALL;
++
++        provided pointcut   Ethernet::create_device;
++    }
++
++    provided sequence   Ethernet::exit(PCI::Device)
++    {
++        provided chunk  ::CALL;
++        provided chunk  PCI::pci_remove_hook;
++
++        provided pointcut   Ethernet::destroy_device;
++    }
++}
 diff --git a/rathaxes/samples/lkm/lkm.blt b/rathaxes/samples/lkm/lkm.blt
---- a/rathaxes/samples/lkm/lkm.blt
+new file mode 100644
+--- /dev/null
 +++ b/rathaxes/samples/lkm/lkm.blt
-@@ -12,9 +12,6 @@
-         {
-             #include <linux/module.h>
-             #include <linux/kernel.h>
--
--            typedef int  include_linux_module_stamp;
--            typedef int  include_linux_kernel_stamp;
-         }
- 
-         chunk   LKM::data()
+@@ -0,0 +1,55 @@
++with LKM
++{
++    /* Skel of the generated C file: */
++    ${pointcut LKM::includes};
++    ${pointcut LKM::prototypes};
++    ${pointcut LKM::data};
++    ${pointcut LKM::code};
++
++    template sequence   LKM::init()
++    {
++        chunk   LKM::includes()
++        {
++            #include <linux/module.h>
++            #include <linux/kernel.h>
++        }
++
++        chunk   LKM::data()
++        {
++            MODULE_DESCRIPTION(${config.description});
++            MODULE_AUTHOR(${config.author});
++            MODULE_LICENSE(${config.license});
++        }
++
++        chunk   LKM::code()
++        {
++            /*
++             * Rathaxes doesn't yet support arbitrary "decorators" like __init
++             * or __exit.
++             */
++            static int __attribute__((__section__(".init.text")))  rtx_module_init(void)
++            {
++                ${pointcut ::IMPLEMENTATION};
++                ${pointcut LKM::init_bus_hook};
++
++                return 0;
++            }
++
++            module_init(rtx_module_init);
++        }
++    }
++
++    template sequence   LKM::exit()
++    {
++        chunk   LKM::code()
++        {
++            static void __attribute__((__section__(".exit.text")))   rtx_module_exit(void)
++            {
++                ${pointcut ::IMPLEMENTATION};
++                ${pointcut LKM::deinit_bus_hook};
++            }
++
++            module_exit(rtx_module_exit);
++        }
++    }
++}
+diff --git a/rathaxes/samples/lkm/lkm.rti b/rathaxes/samples/lkm/lkm.rti
+new file mode 100644
+--- /dev/null
++++ b/rathaxes/samples/lkm/lkm.rti
+@@ -0,0 +1,25 @@
++interface LKM
++{
++    provided pointcut   LKM::includes;
++    /* maybe it should be possible to use chunk ::decl in sequence templates? */
++    provided pointcut   LKM::prototypes;
++    provided pointcut   LKM::data;
++    provided pointcut   LKM::code;
++
++    required variable ::string  LKM::author;
++    required variable ::string  LKM::description;
++    required variable ::string  LKM::license;
++
++    required sequence   LKM::init()
++    {
++        provided chunk      LKM::includes;
++        provided chunk      LKM::code;
++        provided pointcut   LKM::init_bus_hook;
++    }
++
++    required sequence   LKM::exit()
++    {
++        provided chunk      LKM::code;
++        provided pointcut   LKM::deinit_bus_hook;
++    }
++}
 diff --git a/rathaxes/samples/lkm/lkm.rtx b/rathaxes/samples/lkm/lkm.rtx
---- a/rathaxes/samples/lkm/lkm.rtx
+new file mode 100644
+--- /dev/null
 +++ b/rathaxes/samples/lkm/lkm.rtx
-@@ -1,4 +1,4 @@
--device LKM use LKM, PCI, Log
+@@ -0,0 +1,46 @@
 +device LKM use LKM, PCI, Ethernet, Log
- {
-     Ethernet::open(Ethernet::Device dev)
-     {
++{
++    Ethernet::open(Ethernet::Device dev)
++    {
++        Log::info("Open the device");
++    }
++
++    Ethernet::close(Ethernet::Device dev)
++    {
++        Log::info("Close the device");
++    }
++
++    Ethernet::interrupt_handler(Ethernet::Device dev)
++    {
++        Log::info("Got an interruption");
++    }
++
++    Ethernet::send(Ethernet::Device dev, Socket::SKBuff skb)
++    {
++        Log::info("We have one packet to transmit!");
++    }
++
++    LKM::init()
++    {
++        Log::info("Hello this is LKM");
++    }
++
++    LKM::exit()
++    {
++        Log::info("Good bye this was LKM");
++    }
++}
++
++configuration
++{
++    LKM::name = "hello";
++    LKM::author = "Rathaxes";
++    LKM::description = "Hello World Loadable Kernel Module (LKM)";
++    LKM::license = "GPL";
++
++    PCI::vendor_id = 0x8086;
++    PCI::product_id = 0x100f;
++    PCI::set_master = true;
++
++    Ethernet::ifname = "rtx%d";
++}
+diff --git a/rathaxes/samples/lkm/log.blt b/rathaxes/samples/lkm/log.blt
+new file mode 100644
+--- /dev/null
++++ b/rathaxes/samples/lkm/log.blt
+@@ -0,0 +1,10 @@
++with Log
++{
++    template sequence   Log::info(::string msg)
++    {
++        chunk   ::CALL
++        {
++            pr_info("%s\n", ${msg});
++        }
++    }
++}
+diff --git a/rathaxes/samples/lkm/log.rti b/rathaxes/samples/lkm/log.rti
+new file mode 100644
+--- /dev/null
++++ b/rathaxes/samples/lkm/log.rti
+@@ -0,0 +1,7 @@
++interface Log
++{
++    provided sequence   Log::info(::string)
++    {
++        provided chunk  ::CALL;
++    }
++}
 diff --git a/rathaxes/samples/lkm/pci.blt b/rathaxes/samples/lkm/pci.blt
---- a/rathaxes/samples/lkm/pci.blt
+new file mode 100644
+--- /dev/null
 +++ b/rathaxes/samples/lkm/pci.blt
-@@ -5,8 +5,6 @@
-         chunk   LKM::includes()
-         {
-             #include <linux/pci.h>
--
--            typedef int include_linux_pci_stamp;
-         }
- 
-         chunk   ::decl()
-@@ -24,16 +22,6 @@
-         }
-     }
- 
--    /*
--     * The PCI::probe sequence is a "required" sequence which means that its
--     * implementation will be done in the .rtx. Here we just define the context
--     * were this implementation will be inserted. The implementation should be
--     * able to access to the struct pci_dev (here marked as the "argument"
--     * PCI::Device). How do we bind this PCI::Device argument with the pdev
--     * struct pci_dev pointer defined in the LKM::code chunk?
--     *
--     * The only thing I can imagine is: ${pointcut ::IMPLEMENTATION(pdev)};
--     */
-     template sequence   PCI::probe(PCI::Device pdev)
-     {
-         chunk LKM::prototypes()
-@@ -112,22 +100,32 @@
- 
-         chunk LKM::init_bus_hook()
-         {
--            /*
--             * So how do we use the return value in the parent context?
--             */
-             int error;
-             if ((error = pci_register_driver(&rtx_pci_driver)))
-             {
-                  ${Log::info("Cannot register pci driver")};
--                 // should we return here.
--                 // error managmement procedure has to be determined ASAP.
+@@ -0,0 +1,143 @@
++with PCI, LKM, Log
++{
++    template type   PCI::Device()
++    {
++        chunk   LKM::includes()
++        {
++            #include <linux/pci.h>
++        }
++
++        chunk   ::decl()
++        {
++            struct pci_dev;
++        }
++
++        chunk   ::init(pci_dev)
++        {
++            ${self} = ${pci_dev};
++        }
++
++        map
++        {
++        }
++    }
++
++    template sequence   PCI::probe(PCI::Device pdev)
++    {
++        chunk LKM::prototypes()
++        {
++            static int /* __devinit */  rtx_pci_probe(struct pci_dev *,
++                                                      const struct pci_device_id *);
++        }
++
++        chunk LKM::code()
++        {
++            static int /* __devinit */  rtx_pci_probe(struct pci_dev *pdev,
++                                                      const struct pci_device_id *pdev_id)
++            {
++                int             err;
++
++                err = pci_enable_device(pdev);
++                if (err < 0)
++                    goto fail;
++
++                ${pointcut PCI::pci_probe_hook};
++
++                return 0;
++
++                fail:
++                    return err;
++            }
++        }
++
++        chunk   ::CALL
++        {
++        }
++    }
++
++    template sequence   PCI::remove(PCI::Device pdev)
++    {
++        chunk LKM::prototypes()
++        {
++            static void rtx_pci_remove(struct pci_dev *);
++        }
++
++        chunk LKM::code()
++        {
++            static void rtx_pci_remove(struct pci_dev *pdev)
++            {
++                ${pointcut PCI::pci_remove_hook};
++
++                pci_disable_device(pdev);
++            }
++        }
++
++        chunk   ::CALL()
++        {
++        }
++    }
++
++    template sequence   PCI::register()
++    {
++        chunk LKM::data()
++        {
++            /*
++             * CNorm doesn't seem to like "dynamic" arrays (i.e: you always
++             * have to specify the exact size).
++             */
++            static struct pci_device_id rtx_pci_device_table[2] = {
++                { ${config.vendor_id}, ${config.product_id}, PCI_ANY_ID, PCI_ANY_ID },
++                { 0, }
++            };
++
++            static struct pci_driver rtx_pci_driver = {
++                .name = ${config.name},
++                .id_table = rtx_pci_device_table,
++                .probe = rtx_pci_probe,
++                .remove = rtx_pci_remove
++            };
++        }
++
++        chunk LKM::init_bus_hook()
++        {
++            int error;
++            if ((error = pci_register_driver(&rtx_pci_driver)))
++            {
++                 ${Log::info("Cannot register pci driver")};
 +                 /*
 +                  * So we catched the error but how do we return it to the
 +                  * parent context?
@@ -183,13 +686,12 @@
 +                  * a coincidence (and, in this case, *we* wrote the parent
 +                  * context).
 +                  */
-                  return error;
-             }
-         }
- 
-         chunk ::CALL()
-         {
--            // no implementation, we just need to instrument the lkm::bus_hook
++                 return error;
++            }
++        }
++
++        chunk ::CALL()
++        {
 +            /*
 +             * The implementation of ::CALL is empty. This template sequence is
 +             * actually not provided nor required.
@@ -198,21 +700,100 @@
 +             * itself in the hook LKM::init_bus_hook for which this sequence
 +             * has a chunk (see above chunk).
 +             */
-         }
-     }
- 
++        }
++    }
++
++    template sequence   PCI::unregister()
++    {
++        chunk   LKM::deinit_bus_hook()
++        {
++            pci_unregister_driver(&rtx_pci_driver);
++        }
++
++        chunk ::CALL
++        {
++        }
++    }
++}
 diff --git a/rathaxes/samples/lkm/pci.rti b/rathaxes/samples/lkm/pci.rti
---- a/rathaxes/samples/lkm/pci.rti
+new file mode 100644
+--- /dev/null
 +++ b/rathaxes/samples/lkm/pci.rti
-@@ -7,11 +7,6 @@
- 
-     provided sequence   PCI::register()
-     {
--        // it is impossible to provide a "dummy" sequence
--        // which just hook itself. The PCI:register juste
--        // inject its code in the module_init function
--        // in order to load the pci driver.
--        // Everything is done with the configuration.
-         provided chunk  ::CALL;
-         provided chunk  LKM::data;
-         provided chunk  LKM::init_bus_hook;
+@@ -0,0 +1,36 @@
++interface PCI : LKM
++{
++    provided type       PCI::Device;
++
++    required variable ::number  PCI::vendor_id;
++    required variable ::number  PCI::product_id;
++
++    provided sequence   PCI::register()
++    {
++        provided chunk  ::CALL;
++        provided chunk  LKM::data;
++        provided chunk  LKM::init_bus_hook;
++    }
++
++    provided sequence   PCI::unregister()
++    {
++        provided chunk  ::CALL;
++        provided chunk  LKM::deinit_bus_hook;
++    }
++
++    provided sequence   PCI::probe(PCI::Device)
++    {
++        provided chunk  LKM::prototypes;
++        provided chunk  LKM::code;
++
++        provided pointcut   PCI::pci_probe_hook;
++    }
++
++    provided sequence   PCI::remove(PCI::Device)
++    {
++        provided chunk  LKM::prototypes;
++        provided chunk  LKM::code;
++
++        provided pointcut   PCI::pci_remove_hook;
++    }
++}
+diff --git a/rathaxes/samples/lkm/socket.blt b/rathaxes/samples/lkm/socket.blt
+new file mode 100644
+--- /dev/null
++++ b/rathaxes/samples/lkm/socket.blt
+@@ -0,0 +1,27 @@
++with Socket, LKM
++{
++    template type Socket::SKBuff()
++    {
++        chunk LKM::includes()
++        {
++            #include <linux/skbuff.h>
++        }
++
++        chunk ::decl()
++        {
++            struct sk_buff;
++        }
++
++        chunk ::init()
++        {
++        }
++
++        map
++        {
++            // some work may have to be done here in order
++            // to access to some field of the sk_buff.
++            // We should determine if all the sk_buff managment
++            // can be abstracted from the user.
++        }
++    }
++}
+diff --git a/rathaxes/samples/lkm/socket.rti b/rathaxes/samples/lkm/socket.rti
+new file mode 100644
+--- /dev/null
++++ b/rathaxes/samples/lkm/socket.rti
+@@ -0,0 +1,4 @@
++interface Socket : LKM
++{
++    provided type Socket::SKBuff;
++}