#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
// #include "hsHello_stub.h"

MODULE_LICENSE("Dual BSD/GPL");

#define ALLOC_MODE GFP_ATOMIC // GFP_KERNEL

extern int __attribute__((regparm(3))) hello();
extern int __attribute__((regparm(3))) goodbye();

// This is needed for the RTS - don't delcare it regparm3!
void __attribute__((regparm(0))) *malloc(size_t sz)
{
    int i;
    void *p;
//    printk("Attemping to kmalloc 0x%x bytes\n", sz);
    p = kmalloc(sz, ALLOC_MODE);
    i = printk("Acquired pointer of 0x%p to 0x%x bytes\n", p, sz);
    return p;
}

// This is needed for the RTS - don't delcare it regparm3!
void  __attribute__((regparm(0)))free(const void *p)
{
	int i;
	i = printk("Freeing pointer: 0x%p\n", p);
	kfree(p);
}

// This is needed for the RTS - don't delcare it regparm3!
void __attribute__((regparm(0))) *realloc(void *p, size_t s)
{
    void *t;
    t = krealloc(p, s, ALLOC_MODE);
    return t;
}

// This is needed for the RTS - don't delcare it regparm3!
void __attribute__((regparm(0))) *calloc(size_t elem, size_t elem_size)
{
    void *p;
//    printk("Attempting to kcalloc %d elems of %d size\n", elem, elem_size);
    p = kcalloc (elem, elem_size, ALLOC_MODE);
    printk("Allocated: calloc got a pointer 0x%p of elem 0x%x and size 0x%x\n", p, elem, elem_size);
    return p;
}

static int hello_init(void)
{
    int h;
    printk(KERN_ALERT "Hello C world\n");
    h = hello();
    printk(KERN_ALERT "Haskell gave us: %d\n", h);
    return 0;
}
static void hello_exit(void)
{
    int g;
    g = goodbye();
    printk(KERN_ALERT "Haskell gave us: %d\n", g);
    printk(KERN_ALERT "Goodbye C world\n");
}
module_init(hello_init);
module_exit(hello_exit);
