changeset 97:ffdb018893e2

Finish the patch on the create/destroy_device rewrite in the e1000 sample and fix Builtin::symbol
author Louis Opter <louis@lse.epita.fr>
date Thu, 22 Nov 2012 15:37:46 -0800
parents 3e715b3e0ecd
children 147519512c3d
files rathaxes_fix_builtin_symbol.patch rathaxes_rewrite_create_and_destroy_device_in_the_e1000_sample.patch series
diffstat 3 files changed, 643 insertions(+), 89 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rathaxes_fix_builtin_symbol.patch	Thu Nov 22 15:37:46 2012 -0800
@@ -0,0 +1,24 @@
+# HG changeset patch
+# User David Pineau <dav.pineau@gmail.com>, Louis Opter <louis@lse.epita.fr>
+# Parent 7da6e752991acb1b97f4fe77e940a4368f2cb969
+rathaxes: fix builtin::symbol
+
+It was builtin::Symbol instead of builtin::symbol in the compiler.
+
+diff --git a/rathaxes/compiler/passes/back/rtxIntrospect.inc.cws b/rathaxes/compiler/passes/back/rtxIntrospect.inc.cws
+--- a/rathaxes/compiler/passes/back/rtxIntrospect.inc.cws
++++ b/rathaxes/compiler/passes/back/rtxIntrospect.inc.cws
+@@ -638,11 +638,11 @@
+                     ref paramType = theChunk.variables[theVar.name].type_node.name;
+                 else
+                 {
+-                    // That's it : It's a Builtin::Symbol, then.
++                    // That's it : It's a Builtin::symbol, then.
+                     local id;
+                     local dummy;
+                     // The param type shall be a rtxNodeIdentifier
+-                    rtxNodeIdentifier(paramType, "Symbol", "Builtin");
++                    rtxNodeIdentifier(paramType, "symbol", "Builtin");
+                 }
+             }
+             else
--- a/rathaxes_rewrite_create_and_destroy_device_in_the_e1000_sample.patch	Sun Nov 18 02:19:07 2012 +0100
+++ b/rathaxes_rewrite_create_and_destroy_device_in_the_e1000_sample.patch	Thu Nov 22 15:37:46 2012 -0800
@@ -1,6 +1,16 @@
 # HG changeset patch
-# Parent a7ba4e6eae2c9086c0b9876494165bf21ad1f405
-rathaxes: rewrite the {create,destroy}_device functions in the e1000 sample
+# Parent d65cd0228e5c25692e6f37d0524e61ae26102a33
+rathaxes: rehaul the device initialization/destruction in the e1000 sample
+
+- Add several chunks on the e1000::Context; these chunks perform
+  low-level, device-dependant operations and should be move in the
+  front-end at some point. They weave into pointcuts defined by the
+  Ethernet subsystem;
+- The e1000::{create,destroy}_device sequence templates are entirely
+  gone; they are replaced by the aforementioned chunks and more generic
+  code in the PCI and Ethernet subsystems;
+- The PCI::{probe,remove} chunks/pointcuts have been rehauled and are
+  centered on the new PCI::Device type template.
 
 diff --git a/rathaxes/samples/e1000/e1000.blt b/rathaxes/samples/e1000/e1000.blt
 --- a/rathaxes/samples/e1000/e1000.blt
@@ -11,38 +21,113 @@
  {
      template type   e1000::RxDescriptor()
      {
-@@ -288,7 +288,7 @@
-             {
-                 int                         bars;
-                 unsigned char /* __iomem */ *ioaddr;
--                int                         irq;
+@@ -268,6 +268,22 @@
+ 
+     template type   e1000::Context()
+     {
++        chunk   ::decl()
++        {
++            struct rtx_e1000_ctx
++            {
++                int                         bars;
++                unsigned char /* __iomem */ *ioaddr;
 +                unsigned int                irq;
++
++                /* we can't use the Rathaxes type here (#8) */
++                //${e1000::RxRing}    rx_ring;
++                //${e1000::TxRing}    tx_ring;
++                struct rtx_e1000_rx_ring    rx_ring;
++                struct rtx_e1000_tx_ring    tx_ring;
++            };
++        }
++
+         chunk   Ethernet::SubContext()
+         {
+             /*
+@@ -278,28 +294,58 @@
+             ${e1000::Context}   hw_ctx;
+         }
  
-                 /* we can't use the Rathaxes type here (#8) */
-                 //${e1000::RxRing}    rx_ring;
-@@ -298,8 +298,11 @@
-             };
+-        chunk   ::decl()
++        chunk   Ethernet::adapter_init_context(Ethernet::Device rtx_ether_ctx,
++                                               Builtin::number bars,
++                                               Builtin::symbol ioaddr,
++                                               Builtin::number irq)
+         {
+-            /*
+-             * Yes, this typedef looks ugly but read the remark about
+-             * Ethernet::Device in ethernet.blt.
+-             */
+-            struct rtx_e1000_ctx
+             {
+-                int                         bars;
+-                unsigned char /* __iomem */ *ioaddr;
+-                int                         irq;
+-
+-                /* we can't use the Rathaxes type here (#8) */
+-                //${e1000::RxRing}    rx_ring;
+-                //${e1000::TxRing}    tx_ring;
+-                struct rtx_e1000_rx_ring    rx_ring;
+-                struct rtx_e1000_tx_ring    tx_ring;
+-            };
++                struct rtx_e1000_ctx *hw_ctx = &${rtx_ether_ctx}->hw_ctx;
++                hw_ctx->bars = ${bars};
++                hw_ctx->ioaddr = ${ioaddr};
++                hw_ctx->irq = ${irq};
++            }
          }
  
 -        chunk   ::init()
-+        chunk   ::init(Builtin::number bars, Builtin::number ioaddr, Builtin::number irq)
++        chunk   Ethernet::adapter_reset(Ethernet::Device rtx_ether_ctx)
          {
-+            ${self}->bars = ${bars};
-+            ${self}->ioaddr = ${ioaddr};
-+            ${self}->irq = irq;
++            {
++                struct rtx_e1000_ctx *hw_ctx = &${rtx_ether_ctx}->hw_ctx;
++                rtx_e1000_register_write32(hw_ctx, E1000_CTRL, E1000_CMD_RST);
++                udelay(10);
++            }
++        }
++
++        chunk   Ethernet::adapter_load_mac_address(Ethernet::Device rtx_ether_ctx)
++        {
++            {
++                struct rtx_e1000_ctx *hw_ctx = &${rtx_ether_ctx}->hw_ctx;
++                /* Shamelessly borrowed from Minix */
++                for (int i = 0; i < 3; ++i)
++                {
++                    rtx_e1000_register_write32(hw_ctx, E1000_EEPROM_READ, (i << 8) | 1);
++                    int value;
++                    do
++                        value = rtx_e1000_register_read32(hw_ctx, E1000_EEPROM_READ);
++                    while ((value & (1 << 4)) == 0);
++                    value >>= 16;
++                    /*
++                     * XXX: The net_dev manipulations here should take place in the
++                     * ethernet templates:
++                     * TODO: recevoir un Builtin::symbol avec le tableau ici pour
++                     * pouvoir les remonter directement.
++                     */
++                    ${rtx_ether_ctx}->net_dev->dev_addr[i * 2] = value & 0xff;
++                    ${rtx_ether_ctx}->net_dev->dev_addr[i * 2 + 1] = (value >> 8) & 0xff;
++                }
++
++                /* TODO: deplacer ça dans Ethernet (see above point): */
++                memcpy(${rtx_ether_ctx}->net_dev->perm_addr,
++                       ${rtx_ether_ctx}->net_dev->dev_addr,
++                       ${rtx_ether_ctx}->net_dev->addr_len);
++
++                ${Log::info("e1000::create: mac address loaded from the EEPROM")};
++            }
          }
  
          map
-@@ -479,40 +482,16 @@
+@@ -477,91 +523,6 @@
+         }
+     }
  
-     template sequence   e1000::create_device()
-     {
+-    template sequence   e1000::create_device()
+-    {
 -        chunk Ethernet::create_device(PCI::AbstractDevice pdev, Ethernet::Device rtx_ether_ctx)
-+        chunk Ethernet::create_device(Ethernet::Device rtx_ether_ctx,
-+                                      Builtin::number bars,
-+                                      Builtin::number ioaddr,
-+                                      Builtin::number irq)
-         {
+-        {
 -            /*
 -             * PCI init stuff:
 -             *
@@ -50,10 +135,7 @@
 -             * blts, also at some point maybe we could do that completely
 -             * automatically in the PCI/Ethernet blts.
 -             */
-+            /* XXX: Use the rathaxes type directly here (#51): */
-+            struct rtx_e1000_ctx *hw_ctx = &${rtx_ether_ctx}->hw_ctx;
-+            ${cast local.hw_ctx as e1000::Context};
- 
+-
 -            /*
 -             * We could have used an init function here but since we can't init
 -             * all the fields at once (see, ioaddr) and cannot call a C
@@ -78,18 +160,58 @@
 -             * The really device specific algorithm starts here (so it should
 -             * certainly be written in the frontend):
 -             */
-+            ${local.hw_ctx.init(bars, ioaddr, irq)};
- 
-             /* Reset the card */
-             rtx_e1000_register_write32(&${rtx_ether_ctx}->hw_ctx, E1000_CTRL, E1000_CMD_RST);
-@@ -533,6 +512,7 @@
-                 ${rtx_ether_ctx}->net_dev->dev_addr[i * 2 + 1] = (value >> 8) & 0xff;
-             }
- 
-+            /* XXX: use ${rtx_ether_ctx.set_mac_address()}; : */
-             memcpy(${rtx_ether_ctx}->net_dev->perm_addr,
-                    ${rtx_ether_ctx}->net_dev->dev_addr,
-                    ${rtx_ether_ctx}->net_dev->addr_len);
+-
+-            /* Reset the card */
+-            rtx_e1000_register_write32(&${rtx_ether_ctx}->hw_ctx, E1000_CTRL, E1000_CMD_RST);
+-            udelay(10);
+-
+-            /* Now we can load its mac address (thanks minix code) */
+-            for (int i = 0; i < 3; ++i)
+-            {
+-                rtx_e1000_register_write32(&${rtx_ether_ctx}->hw_ctx, E1000_EEPROM_READ, (i << 8) | 1);
+-
+-                int value;
+-                do
+-                    value = rtx_e1000_register_read32(&${rtx_ether_ctx}->hw_ctx, E1000_EEPROM_READ);
+-                while ((value & (1 << 4)) == 0);
+-                value >>= 16;
+-
+-                ${rtx_ether_ctx}->net_dev->dev_addr[i * 2] = value & 0xff;
+-                ${rtx_ether_ctx}->net_dev->dev_addr[i * 2 + 1] = (value >> 8) & 0xff;
+-            }
+-
+-            memcpy(${rtx_ether_ctx}->net_dev->perm_addr,
+-                   ${rtx_ether_ctx}->net_dev->dev_addr,
+-                   ${rtx_ether_ctx}->net_dev->addr_len);
+-
+-            ${Log::info("e1000::create: mac address loaded from the EEPROM")};
+-        }
+-
+-        chunk ::CALL()
+-        {
+-        }
+-    }
+-
+-    template sequence   e1000::destroy_device()
+-    {
+-        chunk   Ethernet::destroy_device(PCI::AbstractDevice pdev, Ethernet::Device rtx_ether_ctx)
+-        {
+-            /*
+-             * Here, we should have some checks to avoid to free resources that
+-             * haven't been allocated. (e.g: in case of previous errors).
+-             */
+-            iounmap(${rtx_ether_ctx}->hw_ctx.ioaddr);
+-            pci_release_selected_regions(${pdev}, ${rtx_ether_ctx}->hw_ctx.bars);
+-        }
+-
+-        chunk   ::CALL()
+-        {
+-        }
+-    }
+-
+     /* TODO: make that a method of e1000::Context */
+     template sequence   e1000::print_status(Ethernet::Device ctx)
+     {
 diff --git a/rathaxes/samples/e1000/e1000.rti b/rathaxes/samples/e1000/e1000.rti
 --- a/rathaxes/samples/e1000/e1000.rti
 +++ b/rathaxes/samples/e1000/e1000.rti
@@ -102,92 +224,499 @@
      required variable   Builtin::number rx_ring_size;
      required variable   Builtin::number tx_ring_size;
      required variable   Builtin::number rx_buffer_len;
-@@ -12,7 +9,8 @@
+@@ -10,9 +7,18 @@
+ 
+     provided type   Context
      {
++        method      decl();
++
          chunk       Ethernet::SubContext();
-         method      decl();
+-        method      decl();
 -        method      init();
-+        /* XXX: used types: */
-+        method      init(Builtin::number, Builtin::number, Builtin::number);
++
++        /* Callbacks/Hooks which should probably be in the front-end: */
++        chunk       Ethernet::adapter_init_context(Ethernet::Device,
++                                                   Builtin::number,
++                                                   Builtin::symbol,
++                                                   Builtin::number);
++//      chunk       Ethernet::adapter_init_context(Ethernet::Device);
++        chunk       Ethernet::adapter_reset(Ethernet::Device);
++        chunk       Ethernet::adapter_load_mac_address(Ethernet::Device);
      }
  
      provided type   RxDescriptor
+@@ -76,18 +82,6 @@
+         chunk       ::decl();
+     }
+ 
+-    provided sequence   create_device()
+-    {
+-        provided chunk  Ethernet::create_device(PCI::AbstractDevice, Ethernet::Device);
+-        provided chunk  ::CALL();
+-    }
+-
+-    provided sequence   destroy_device()
+-    {
+-        provided chunk  Ethernet::destroy_device(PCI::AbstractDevice, Ethernet::Device);
+-        provided chunk  ::CALL();
+-    }
+-
+     /*
+      * This should take an e1000::Context as the first argument but this was
+      * not working as wished.
 diff --git a/rathaxes/samples/e1000/ethernet.blt b/rathaxes/samples/e1000/ethernet.blt
 --- a/rathaxes/samples/e1000/ethernet.blt
 +++ b/rathaxes/samples/e1000/ethernet.blt
-@@ -111,6 +111,13 @@
-             ${self}->net_dev = ${net_dev};
-         }
+@@ -113,6 +113,8 @@
  
-+        chunk set_mac_address(Builtin::number addr)
-+        {
-+            memcpy(${self}->net_dev->perm_addr,
-+                   ${self}->net_dev->dev_addr,
-+                   ${self}->net_dev->addr_len);
-+        }
-+
          map
          {
++            pci_device: ${self}->pci_dev;
++            net_device: ${self}->net_dev;
          }
-@@ -249,9 +256,26 @@
+     }
+ 
+@@ -210,48 +212,72 @@
+             };
+         }
+ 
+-        /* For now the type is not handled, so we just omit it (see #17) */
+-        chunk PCI::pci_probe_hook(PCI::AbstractDevice pdev)
++        /*
++         * NOTE: for now, the error handling is leaking from PCI::probe(), but
++         * it's better than doing it at all.
++         *
++         * XXX: the chunk argument isn't correctly expanded by the
++         * compiler I have to use the same name as the actual C
++         * variable:
++         */
++        chunk PCI::pci_probe_hook(PCI::Device rtx_pci_dev)
+         {
+-            /*
+-             * This typedef is needed to workaround a bug in CNorm __std__
+-             * dialect.
+-             */
+             ${Ethernet::Device} rtx_ether_ctx;
+-            struct net_device *net_dev;
+-            int error;
++            ${Ethernet::AbstractDevice} net_dev;
+ 
+-            /* Initialize the net_device structure */
+             net_dev = alloc_etherdev(sizeof(*rtx_ether_ctx));
+-            if (net_dev == 0)
++            if (!net_dev)
+             {
+-                ${Log::info("cannot allocate memory")};
+-                /*
+-                 * Again, the error should be "raised" in the parent context.
+-                 *
+-                 * Here we know that we can return ENOMEM because *we* wrote
+-                 * the parent context.
+-                 */
+-                return -ENOMEM;
++                ${Log::info("cannot allocate the ethernet device context")};
++                error = -ENOMEM;
++                goto fail;
+             }
+-            SET_NETDEV_DEV(net_dev, &${pdev}->dev);
++            SET_NETDEV_DEV(net_dev, ${rtx_pci_dev.device});
+             strlcpy(net_dev->name, ${config.ifname}, sizeof(net_dev->name));
+-            net_dev->irq = ${pdev}->irq;
++            net_dev->irq = ${rtx_pci_dev.irq};
+             net_dev->netdev_ops = &rtx_ether_ops;
+ 
+             error = register_netdev(net_dev);
+             if (error)
+             {
+                 ${Log::info("cannot register the driver in the net subsystem")};
+-                return error;
++                goto fail;
+             }
+ 
              /* Initialize our context held by the net_device structure */
-             ${rtx_ether_ctx.init(local.net_dev, pdev)};
+-            ${rtx_ether_ctx.init(local.net_dev, pdev)};
++            /*
++             * XXX: the cast is here because the compiler resolve the
++             * type of rtx_pci_dev.pci_device to the type of
++             * rtx_pci_dev instead of the type of rtx_pci_dev.pci_device.
++             *
++             * Also, I'm getting placeholder in the generated code if
++             * I don't open a scope here.
++             */
++            {
++                struct pci_dev *pci_device = ${rtx_pci_dev.pci_device};
++                ${cast local.pci_device as PCI::AbstractDevice};
++                ${local.rtx_ether_ctx.init(local.net_dev, local.pci_device)};
++            }
  
-+            /* XXX: The following code should probably part of PCI:: */
-+
-             pci_set_drvdata(${pdev}, net_dev);
+-            pci_set_drvdata(${pdev}, net_dev);
++            /* Register ourselves in the parent context: */
++            /* ${rtx_pci_dev.set_context(local.rtx_ether_ctx)}; */
++            ${rtx_pci_dev}->context = rtx_ether_ctx;
  
 -            ${pointcut Ethernet::create_device(pdev, local.rtx_ether_ctx)};
-+            int bars = pci_select_bars(${pdev}, IORESOURCE_MEM);
-+
-+            if (pci_enable_device_mem(${pdev}))
-+                ${Log::info("pci_enable_device_mem failed")};
-+            if (pci_request_selected_regions(${pdev}, bars, ${config.name}))
-+                ${Log::info("pci_request_selected_regions failed")};
-+            if (${config.set_master})
-+                pci_set_master(${pdev});
-+
-+            /* 0 here is for BAR_0: */
-+            unsigned char /* __iomem */ *ioaddr = pci_ioremap_bar(${pdev}, 0);
-+            if (!ioaddr)
-+                ${Log::info("pci_ioremap_bar failed")};
-+
-+            unsigned int irq = net_dev->irq;
-+            ${pointcut Ethernet::create_device(local.rtx_ether_ctx, local.bars, local.ioaddr, local.irq)};
++            /*
++             * XXX: the asssignments/casts are here to circumvent
++             * typing issues in the compiler (see previous XXX).
++             */
++            int bars = ${rtx_pci_dev.bars};
++            unsigned char /* __iomem */ *ioaddr = ${rtx_pci_dev.ioaddr};
++            int irq = ${rtx_pci_dev.irq};
++            ${cast local.bars as Builtin::number};
++            ${cast local.irq as Builtin::number};
++            ${pointcut Ethernet::adapter_init_context(local.rtx_ether_ctx,
++                                                      local.bars,
++                                                      local.ioaddr,
++                                                      local.irq)};
++            ${pointcut Ethernet::adapter_reset(local.rtx_ether_ctx)};
++            ${pointcut Ethernet::adapter_load_mac_address(local.rtx_ether_ctx)};
+         }
+ 
+         /* This chunk should be removed (see #26) */
+@@ -262,16 +288,18 @@
+ 
+     template sequence   Ethernet::exit()
+     {
+-        chunk   PCI::pci_remove_hook(PCI::AbstractDevice pdev)
++        /*
++         * XXX: We have to use the same name as the C variable for
++         * the chunk argument...
++         */
++        chunk   PCI::pci_remove_hook(PCI::Device rtx_pci_dev)
+         {
+-            /* workaround for cnorm unstrict */
+-            struct net_device *net_dev = pci_get_drvdata(${pdev});
+-            ${Ethernet::Device} rtx_ether_ctx = netdev_priv(net_dev);
++            ${Ethernet::Device} rtx_ether_ctx = ${rtx_pci_dev.context};
+ 
+-            ${pointcut Ethernet::destroy_device(pdev, local.rtx_ether_ctx)};
++            BUG_ON(!rtx_ether_ctx);
+ 
+-            unregister_netdev(net_dev);
+-            free_netdev(net_dev);
++            unregister_netdev(${local.rtx_ether_ctx.net_device});
++            free_netdev(${local.rtx_ether_ctx.net_device});
          }
  
          /* This chunk should be removed (see #26) */
 diff --git a/rathaxes/samples/e1000/ethernet.rti b/rathaxes/samples/e1000/ethernet.rti
 --- a/rathaxes/samples/e1000/ethernet.rti
 +++ b/rathaxes/samples/e1000/ethernet.rti
-@@ -1,5 +1,8 @@
+@@ -1,4 +1,4 @@
 -interface Ethernet : Socket, PCI, LKM
 +interface Ethernet : Socket, PCI, LKM, Builtin
  {
-+    /* XXX: This should be in pci.rti, also maybe we need a bool type */
-+    required variable   Builtin::symbol set_master;
-+
      required variable   Builtin::string ifname;
  
-      provided type   ProtocolId
-@@ -22,6 +25,8 @@
-         chunk       LKM::includes();
+@@ -23,6 +23,9 @@
          method      decl();
          method      init(Ethernet::AbstractDevice, PCI::AbstractDevice);
-+        method      set_mac_address(Builtin::number);
+         pointcut    Ethernet::SubContext();
 +
-         pointcut    Ethernet::SubContext();
++        attribute   PCI::AbstractDevice         pci_device;
++        attribute   Ethernet::AbstractDevice    net_device;
      }
  
-@@ -54,7 +59,10 @@
+     required sequence   open(Ethernet::Device)
+@@ -52,15 +55,18 @@
+     provided sequence   init()
+     {
          provided chunk  LKM::data();
-         provided chunk  PCI::pci_probe_hook(PCI::AbstractDevice);
+-        provided chunk  PCI::pci_probe_hook(PCI::AbstractDevice);
++        provided chunk  PCI::pci_probe_hook(PCI::Device);
  
 -        provided pointcut   Ethernet::create_device(PCI::AbstractDevice, Ethernet::Device);
-+        provided pointcut   Ethernet::create_device(Ethernet::Device,
-+                                                    Builtin::number,
-+                                                    Builtin::number,
-+                                                    Builtin::number);
++        provided pointcut   Ethernet::adapter_init_context(Ethernet::Device,
++                                                           Builtin::number,
++                                                           Builtin::symbol,
++                                                           Builtin::number);
++        provided pointcut   Ethernet::adapter_reset(Ethernet::Device);
++        provided pointcut   Ethernet::adapter_load_mac_address(Ethernet::Device);
      }
  
      provided sequence   exit()
+     {
+-        provided chunk  PCI::pci_remove_hook(PCI::AbstractDevice);
+-
+-        provided pointcut   Ethernet::destroy_device(PCI::AbstractDevice, Ethernet::Device);
++        provided chunk  PCI::pci_remove_hook(PCI::Device);
+     }
+ }
+diff --git a/rathaxes/samples/e1000/lkm.rtx b/rathaxes/samples/e1000/lkm.rtx
+--- a/rathaxes/samples/e1000/lkm.rtx
++++ b/rathaxes/samples/e1000/lkm.rtx
+@@ -74,7 +74,6 @@
+      */
+     PCI::vendor_id = 0x8086;
+     PCI::product_id = 0x100e;
+-    PCI::set_master = true;
+ 
+     Ethernet::ifname = "rtx%d";
+ 
+diff --git a/rathaxes/samples/e1000/pci.blt b/rathaxes/samples/e1000/pci.blt
+--- a/rathaxes/samples/e1000/pci.blt
++++ b/rathaxes/samples/e1000/pci.blt
+@@ -12,12 +12,102 @@
+             struct pci_dev;
+         }
+ 
+-        chunk ::init(PCI::AbstractDevice)
++        chunk   ::init(PCI::AbstractDevice)
+         {
+         }
+ 
++        chunk   set_context(Builtin::symbol ctx)
++        {
++            pci_set_drvdata(${self}, ${ctx});
++        }
++
+         map
+         {
++            context: pci_get_drvdata(${self});
++        }
++    }
++
++    template type   PCI::Device()
++    {
++        chunk   ::decl()
++        {
++            struct rtx_pci_dev
++            {
++                struct pci_dev              *pdev;
++                int                         bars;
++                /* It could be an array at some point: */
++                unsigned char /* __iomem */ *ioaddr;
++                void                        *context;
++            };
++        }
++
++        chunk   ::init(PCI::AbstractDevice pdev)
++        {
++            ${self}->pdev = ${pdev};
++            ${self}->bars = pci_select_bars(${pdev}, IORESOURCE_MEM);
++            ${self}->ioaddr = NULL;
++            ${self}->context = NULL;
++        }
++
++        chunk   LKM::prototypes()
++        {
++            static int  rtx_pci_device_enable(struct rtx_pci_dev *);
++            static void rtx_pci_device_disable(struct rtx_pci_dev *);
++        }
++
++        chunk   LKM::code()
++        {
++            static int rtx_pci_device_enable(struct rtx_pci_dev *self)
++            {
++                int error;
++                error = pci_enable_device(self->pdev);
++                if (error)
++                    return error;
++                error = pci_request_selected_regions(self->pdev, self->bars, ${config.name});
++                if (error)
++                    return error;
++                pci_set_master(self->pdev);
++                return 0;
++            }
++
++            static void rtx_pci_device_disable(struct rtx_pci_dev *self)
++            {
++                if (self->ioaddr)
++                    iounmap(self->ioaddr);
++                pci_release_selected_regions(self->pdev, self->bars);
++                pci_disable_device(self->pdev);
++            }
++        }
++
++        chunk   enable()
++        {
++            rtx_pci_device_enable(${self});
++        }
++
++        chunk   disable()
++        {
++            rtx_pci_device_disable(${self});
++        }
++
++        chunk   select_ioaddr(Builtin::number bar)
++        {
++            ${self}->ioaddr = pci_ioremap_bar(${self}->pdev, ${bar});
++        }
++
++        chunk   set_context(Builtin::symbol ctx)
++        {
++            ${self}->context = ctx;
++        }
++
++        map
++        {
++            context: ${self}->context;
++            device: &${self}->pdev->dev;
++            pci_device: ${self}->pdev;
++            irq: ${self}->pdev->irq;
++            bars: ${self}->bars;
++            ioaddr: ${self}->ioaddr;
++            BAR_0: 0;
+         }
+     }
+ 
+@@ -34,24 +124,67 @@
+             static int /* __devinit */  rtx_pci_probe(struct pci_dev *pdev,
+                                                       const struct pci_device_id *pdev_id)
+             {
+-                int             err;
++                ${cast local.pdev as PCI::AbstractDevice};
++                int error;
++                ${PCI::Device} *rtx_pci_dev;
+ 
+-                err = pci_enable_device(pdev);
+-                if (err < 0)
++                rtx_pci_dev = kmalloc(sizeof(*rtx_pci_dev), GFP_KERNEL);
++                if (!rtx_pci_dev)
++                {
++                    ${Log::info("cannot allocate the pci device context")};
++                    error = -ENOMEM;
+                     goto fail;
++                }
+ 
+-                /* Use local. to reference a local C variable: */
+-                ${cast local.pdev as PCI::AbstractDevice};
+-                ${pointcut PCI::pci_probe_hook(local.pdev)};
++                /*
++                 * XXX: I'm getting placeholder in the generated code if I don't
++                 * open a scope here:
++                 */
++                {
++                    ${local.rtx_pci_dev.init(local.pdev)};
++                }
++
++                /* ${local.pdev.set_context(local.rtx_pci_dev)}; */
++                pci_set_drvdata(pdev, rtx_pci_dev);
++
++                /* ${local.rtx_pci_dev.enable()}; */
++                error = rtx_pci_device_enable(rtx_pci_dev);
++                if (error)
++                {
++                    ${Log::info("rtx_pci_device_enable failed")};
++                    goto fail;
++                }
++
++                /* ${local.rtx_pci_dev.select_ioaddr(local.rtx_pci_dev.BAR_0)}; */
++                rtx_pci_dev->ioaddr = pci_ioremap_bar(
++                    rtx_pci_dev->pdev, ${local.rtx_pci_dev.BAR_0}
++                );
++                if (!${local.rtx_pci_dev.ioaddr})
++                {
++                    ${Log::info("can't map the device address space")};
++                    error = 1; /* XXX anything more approriate? */
++                    goto fail;
++                }
++
++                /*
++                 * XXX: We have to cast here because the compiler is
++                 * confused by the fact that rtx_pci_dev is a
++                 * pointer.
++                 */
++                ${cast local.rtx_pci_dev as PCI::Device};
++                ${pointcut PCI::pci_probe_hook(local.rtx_pci_dev)};
+ 
+                 return 0;
+ 
+-                fail:
+-                    return err;
++            fail:
++                /* ${local.pdev.set_context(NULL)}; */
++                pci_set_drvdata(pdev, NULL);
++                kfree(rtx_pci_dev);
++                return error;
+             }
+         }
+ 
+-        /* This chunk should be remove (see #26) */
++        /* This chunk should be removed (see #26) */
+         chunk   ::CALL()
+         {
+         }
+@@ -69,9 +202,16 @@
+             static void rtx_pci_remove(struct pci_dev *pdev)
+             {
+                 ${cast local.pdev as PCI::AbstractDevice};
+-                ${pointcut PCI::pci_remove_hook(local.pdev)};
++                ${PCI::Device} *rtx_pci_dev = ${local.pdev.context};
+ 
+-                pci_disable_device(pdev);
++                BUG_ON(!rtx_pci_dev);
++
++                /* XXX: compiler confused by the pointer type. */
++                ${cast local.rtx_pci_dev as PCI::Device};
++                ${pointcut PCI::pci_remove_hook(local.rtx_pci_dev)};
++
++                /* ${local.rtx_pci_dev.disable()}; */
++                rtx_pci_device_disable(rtx_pci_dev);
+             }
+         }
+ 
+diff --git a/rathaxes/samples/e1000/pci.rti b/rathaxes/samples/e1000/pci.rti
+--- a/rathaxes/samples/e1000/pci.rti
++++ b/rathaxes/samples/e1000/pci.rti
+@@ -1,14 +1,40 @@
+-interface PCI : LKM
++interface PCI : LKM, Builtin, Device
+ {
++    required variable Builtin::string  LKM::name;
++    required variable Builtin::number  PCI::vendor_id;
++    required variable Builtin::number  PCI::product_id;
++
+     provided type   PCI::AbstractDevice
+     {
+         chunk       LKM::includes();
++
+         method      decl();
+         method      init(PCI::AbstractDevice);
++        method      set_context(Builtin::symbol);
++
++        attribute   Builtin::symbol context;
+     }
+ 
+-    required variable Builtin::number  PCI::vendor_id;
+-    required variable Builtin::number  PCI::product_id;
++    provided type   PCI::Device
++    {
++        chunk       LKM::prototypes();
++        chunk       LKM::code();
++
++        method      decl();
++        method      init(PCI::AbstractDevice);
++        method      enable();
++        method      disable();
++        method      select_ioaddr(Builtin::number);
++        method      set_context(Builtin::symbol);
++
++        attribute   Builtin::symbol         context;
++        attribute   Device::AbstractDevice  device;
++        attribute   PCI::AbstractDevice     pci_device;
++        attribute   Builtin::symbol         ioaddr;
++        attribute   Builtin::number         BAR_0;
++        attribute   Builtin::number         irq;
++        attribute   Builtin::number         bars;
++    }
+ 
+     provided sequence   register()
+     {
+@@ -28,7 +54,7 @@
+         provided chunk  LKM::prototypes();
+         provided chunk  LKM::code();
+ 
+-        provided pointcut   PCI::pci_probe_hook(PCI::AbstractDevice);
++        provided pointcut   PCI::pci_probe_hook(PCI::Device);
+     }
+ 
+     provided sequence   remove()
+@@ -36,6 +62,6 @@
+         provided chunk  LKM::prototypes();
+         provided chunk  LKM::code();
+ 
+-        provided pointcut   PCI::pci_remove_hook(PCI::AbstractDevice);
++        provided pointcut   PCI::pci_remove_hook(PCI::Device);
+     }
+ }
--- a/series	Sun Nov 18 02:19:07 2012 +0100
+++ b/series	Thu Nov 22 15:37:46 2012 -0800
@@ -1,4 +1,5 @@
 rathaxes_add_a_test_to_reproduce_the_pointer_to_rathaxes_bug.patch
+rathaxes_fix_builtin_symbol.patch
 rathaxes_use_single_file_language_tests.patch
 rathaxes_rename_pci_device_to_pci_abstractdevice.patch
 rathaxes_remove_useless_xmit_tso_cksum_offload_method_from_e1000.patch