// hdgl_lattice_sysfs.c
// Linux Kernel Module for live HDGL lattice access via sysfs.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <asm/uaccess.h>

#define LATTICE_SIZE 32
// NOTE: The virtual address mapping must be correct for the system.
#define LATTICE_PHYS_ADDR 0x100000 
#define STEP_INTERVAL_MS 50

static void __iomem *lattice_virt;
static struct kobject *hdgl_kobj;
static struct timer_list lattice_timer;
static spinlock_t lattice_lock;

/* --- Lattice Step Function --- */
static void hdgl_step(struct timer_list *t){
    unsigned long flags;
    spin_lock_irqsave(&lattice_lock, flags);

    // Reading/Writing to the mapped memory region (lattice_virt)
    // ... (Full autonomous step logic as defined in the previous response) ...

    spin_unlock_irqrestore(&lattice_lock, flags);
    mod_timer(&lattice_timer, jiffies + msecs_to_jiffies(STEP_INTERVAL_MS));
}

/* --- Sysfs Attributes --- */
static ssize_t slot_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf){
    unsigned long flags;
    ssize_t ret;
    int idx;
    if(sscanf(attr->attr.name, "D%d", &idx)!=1 || idx<1 || idx>LATTICE_SIZE) return -EINVAL; 
    
    spin_lock_irqsave(&lattice_lock, flags);
    // Read the specific slot from mapped virtual memory
    ret = sprintf(buf, "%lf\n", ioread64(lattice_virt + (idx-1)*sizeof(double)));
    spin_unlock_irqrestore(&lattice_lock, flags);
    return ret;
}

static ssize_t slot_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count){
    unsigned long flags;
    int idx;
    double val;
    if(sscanf(attr->attr.name, "D%d", &idx)!=1 || idx<1 || idx>LATTICE_SIZE) return -EINVAL;
    if(kstrtod(buf, 10, &val)) return -EINVAL;
    
    spin_lock_irqsave(&lattice_lock, flags);
    iowrite64(val, lattice_virt + (idx-1)*sizeof(double));
    spin_unlock_irqrestore(&lattice_lock, flags);
    return count;
}

// Macro to create all 32 sysfs attributes (D1 to D32)
#define HDGL_ATTR(_IDX) \
    struct kobj_attribute D##_IDX##_attr = __ATTR(D##_IDX, 0664, slot_show, slot_store);
HDGL_ATTR(1); HDGL_ATTR(2); HDGL_ATTR(3); HDGL_ATTR(4); HDGL_ATTR(5); HDGL_ATTR(6); HDGL_ATTR(7); HDGL_ATTR(8);
HDGL_ATTR(9); HDGL_ATTR(10); HDGL_ATTR(11); HDGL_ATTR(12); HDGL_ATTR(13); HDGL_ATTR(14); HDGL_ATTR(15); HDGL_ATTR(16);
HDGL_ATTR(17); HDGL_ATTR(18); HDGL_ATTR(19); HDGL_ATTR(20); HDGL_ATTR(21); HDGL_ATTR(22); HDGL_ATTR(23); HDGL_ATTR(24);
HDGL_ATTR(25); HDGL_ATTR(26); HDGL_ATTR(27); HDGL_ATTR(28); HDGL_ATTR(29); HDGL_ATTR(30); HDGL_ATTR(31); HDGL_ATTR(32);

static struct attribute *hdgl_attrs[] = {
    &D1_attr.attr, &D2_attr.attr, &D3_attr.attr, &D4_attr.attr, &D5_attr.attr, &D6_attr.attr, &D7_attr.attr, &D8_attr.attr,
    &D9_attr.attr, &D10_attr.attr, &D11_attr.attr, &D12_attr.attr, &D13_attr.attr, &D14_attr.attr, &D15_attr.attr, &D16_attr.attr,
    &D17_attr.attr, &D18_attr.attr, &D19_attr.attr, &D20_attr.attr, &D21_attr.attr, &D22_attr.attr, &D23_attr.attr, &D24_attr.attr,
    &D25_attr.attr, &D26_attr.attr, &D27_attr.attr, &D28_attr.attr, &D29_attr.attr, &D30_attr.attr, &D31_attr.attr, &D32_attr.attr,
    NULL,
};
ATTRIBUTE_GROUPS(hdgl);

/* --- Module Init/Exit --- */
static int __init hdgl_module_init(void){
    // 1. Map physical memory where the bootloader placed the lattice.
    lattice_virt = ioremap(LATTICE_PHYS_ADDR, LATTICE_SIZE * sizeof(double) + sizeof(double)); // +1 for omega
    if(!lattice_virt){
        printk(KERN_ERR "HDGL: Failed to ioremap lattice memory.\n");
        return -ENOMEM;
    }

    // 2. Create the sysfs directory /sys/hdgl_lattice
    hdgl_kobj = kobject_create_and_add("hdgl_lattice", kernel_kobj);
    if (!hdgl_kobj) return -ENOMEM;
    if (sysfs_create_groups(hdgl_kobj, hdgl_groups)) goto err_sysfs;

    // 3. Setup and start the timer for autonomous stepping.
    spin_lock_init(&lattice_lock);
    timer_setup(&lattice_timer, hdgl_step, 0);
    mod_timer(&lattice_timer, jiffies + msecs_to_jiffies(STEP_INTERVAL_MS));

    printk(KERN_INFO "HDGL Lattice Module loaded. State accessible at /sys/hdgl_lattice\n");
    return 0;

err_sysfs:
    kobject_put(hdgl_kobj);
    iounmap(lattice_virt);
    return -ENOMEM;
}

static void __exit hdgl_module_exit(void){
    del_timer(&lattice_timer);
    sysfs_remove_groups(hdgl_kobj, hdgl_groups);
    kobject_put(hdgl_kobj);
    iounmap(lattice_virt);
    printk(KERN_INFO "HDGL Lattice Module unloaded.\n");
}

module_init(hdgl_module_init);
module_exit(hdgl_module_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("HDGL Team");
MODULE_DESCRIPTION("HDGL Lattice Kernel Module");
MODULE_VERSION("1.0");