# HG changeset patch
# Parent 6e00628ccba9fd82577a8a30fe4e730bc982e987
rathaxes: start to implement the PCI registration part in the LKM sample

diff -r 6e00628ccba9 rathaxes/samples/lkm/CMakeLists.txt
--- a/rathaxes/samples/lkm/CMakeLists.txt	Sat Jan 07 19:07:39 2012 +0100
+++ b/rathaxes/samples/lkm/CMakeLists.txt	Sat Jan 07 19:10:21 2012 +0100
@@ -1,3 +1,7 @@
 ADD_RATHAXES_SOURCES(lkm lkm.rtx
-                     RTI log.rti lkm.rti
-                     BLT log.blt lkm.blt)
+                     RTI log.rti lkm.rti pci.rti
+                     BLT log.blt lkm.blt pci.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 -r 6e00628ccba9 rathaxes/samples/lkm/lkm.blt
--- a/rathaxes/samples/lkm/lkm.blt	Sat Jan 07 19:07:39 2012 +0100
+++ b/rathaxes/samples/lkm/lkm.blt	Sat Jan 07 19:10:21 2012 +0100
@@ -1,8 +1,10 @@
 with LKM
 {
+    /* Skel of the generated C file: */
     ${pointcut LKM::includes};
-    ${pointcut LKM::init};
-    ${pointcut LKM::exit};
+    ${pointcut LKM::prototypes};
+    ${pointcut LKM::data};
+    ${pointcut LKM::code};
 
     template sequence   LKM::init()
     {
@@ -10,22 +12,29 @@
         {
             #include <linux/module.h>
             #include <linux/kernel.h>
-            typedef int  lkm_headers_include_stamp;
 
+            typedef int  include_linux_module_stamp;
+            typedef int  include_linux_kernel_stamp;
+        }
+
+        chunk   LKM::data()
+        {
             MODULE_DESCRIPTION(${config.description});
             MODULE_AUTHOR(${config.author});
             MODULE_LICENSE(${config.license});
         }
 
-        chunk   LKM::init()
+        chunk   LKM::code()
         {
             /*
              * Rathaxes doesn't yet support arbitrary "decorators" like __init
              * or __exit.
              */
-            static int __attribute__((__section__(.init.text)))  rtx_module_init(void)
+            static int __attribute__((__section__(".init.text")))  rtx_module_init(void)
             {
                 ${pointcut ::IMPLEMENTATION};
+
+                return 0;
             }
 
             module_init(rtx_module_init);
@@ -34,14 +43,14 @@
 
     template sequence   LKM::exit()
     {
-        chunk   LKM::exit
+        chunk   LKM::code()
         {
-            static void __attribute((__section__(.exit.text)))   rtx_module_exit(void)
+            static void __attribute__((__section__(".exit.text")))   rtx_module_exit(void)
             {
                 ${pointcut ::IMPLEMENTATION};
             }
 
-            module_exit(rtx_module_init);
+            module_exit(rtx_module_exit);
         }
     }
 }
diff -r 6e00628ccba9 rathaxes/samples/lkm/lkm.rti
--- a/rathaxes/samples/lkm/lkm.rti	Sat Jan 07 19:07:39 2012 +0100
+++ b/rathaxes/samples/lkm/lkm.rti	Sat Jan 07 19:10:21 2012 +0100
@@ -1,8 +1,10 @@
 interface LKM
 {
     provided pointcut   LKM::includes;
-    provided pointcut   LKM::init;
-    provided pointcut   LKM::exit;
+    /* 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;
@@ -11,11 +13,11 @@
     required sequence   LKM::init()
     {
         provided chunk  LKM::includes;
-        provided chunk  LKM::init;
+        provided chunk  LKM::code;
     }
 
     required sequence   LKM::exit()
     {
-        provided chunk  LKM::exit;
+        provided chunk  LKM::code;
     }
 }
diff -r 6e00628ccba9 rathaxes/samples/lkm/lkm.rtx
--- a/rathaxes/samples/lkm/lkm.rtx	Sat Jan 07 19:07:39 2012 +0100
+++ b/rathaxes/samples/lkm/lkm.rtx	Sat Jan 07 19:10:21 2012 +0100
@@ -1,19 +1,35 @@
-device LKM use LKM, Log
+device LKM use LKM, PCI, Log
 {
+    PCI::probe(PCI::Device dev)
+    {
+
+    }
+
+    PCI::remove(PCI::Device dev)
+    {
+
+    }
+
     LKM::init()
     {
         Log::info("Hello this is LKM");
+        PCI::register();
     }
 
     LKM::exit()
     {
         Log::info("Good bye this was LKM");
+        PCI::unregister();
     }
 }
 
 configuration
 {
+    LKM::name = "hello";
     LKM::author = "Rathaxes";
     LKM::description = "Hello World Loadable Kernel Module (LKM)";
     LKM::license = "BSD";
+
+    PCI::vendor_id = 0x8086;
+    PCI::product_id = 0x100f;
 }
diff -r 6e00628ccba9 rathaxes/samples/lkm/pci.blt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rathaxes/samples/lkm/pci.blt	Sat Jan 07 19:10:21 2012 +0100
@@ -0,0 +1,127 @@
+with PCI, LKM, Log
+{
+    template type   PCI::Device()
+    {
+        chunk   LKM::includes()
+        {
+            #include <linux/pci.h>
+
+            typedef int include_linux_pci_stamp;
+        }
+
+        chunk   ::decl()
+        {
+            struct  rtx_pci_device
+            {
+                struct pci_dev  *pci_dev;
+            };
+        }
+
+        chunk   ::init(pci_dev)
+        {
+            ${self}.pci_dev = pci_dev;
+        }
+
+        map
+        {
+        }
+    }
+
+    template sequence   PCI::probe(PCI::Device dev)
+    {
+        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)
+            {
+                /* workaround for CNorm __std__ dialect, shouldn't be here */
+                typedef int ${PCI::Device};
+
+                int             err;
+                ${PCI::Device}  *dev = NULL;
+
+                err = pci_enable_device(pdev);
+                if (err < 0)
+                    goto fail;
+
+                ${pointcut ::IMPLEMENTATION};
+
+                pci_set_drvdata(pdev, dev);
+
+                return 0;
+
+                fail:
+                    return err;
+            }
+        }
+    }
+
+    template sequence   PCI::remove(PCI::Device dev)
+    {
+        chunk LKM::prototypes()
+        {
+            static void rtx_pci_remove(struct pci_dev *);
+        }
+
+        chunk LKM::code()
+        {
+            static void rtx_pci_remove(struct pci_dev *pdev)
+            {
+                pci_disable_device(pdev);
+
+                ${pointcut ::IMPLEMENTATION};
+            }
+        }
+    }
+
+    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}, 0, 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 ::CALL
+        {
+            /*
+             * 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.
+                 return error;
+            }
+        }
+    }
+
+    template sequence   PCI::unregister()
+    {
+        chunk ::CALL
+        {
+            pci_unregister_driver(&rtx_pci_driver);
+        }
+    }
+}
diff -r 6e00628ccba9 rathaxes/samples/lkm/pci.rti
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rathaxes/samples/lkm/pci.rti	Sat Jan 07 19:10:21 2012 +0100
@@ -0,0 +1,30 @@
+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 sequence   PCI::unregister()
+    {
+        provided chunk  ::CALL;
+    }
+
+    required sequence   PCI::probe(PCI::Device)
+    {
+        provided chunk  LKM::prototypes;
+        provided chunk  LKM::code;
+    }
+
+    required sequence   PCI::remove(PCI::Device)
+    {
+        provided chunk  LKM::prototypes;
+        provided chunk  LKM::code;
+    }
+}
