diff --git a/ksudoku.c b/ksudoku.c index a86d705..a39c4f8 100644 --- a/ksudoku.c +++ b/ksudoku.c @@ -1,65 +1,239 @@ -#include "ksudoku.h" +#include +#include +#include +#include +#include #define KSUDOKU_VERSION "0.1" #define KSUDOKU_DESC "Kernel Sudoku Module" +#define KSUDOKU_READY 0 +#define KSUDOKU_BUSY 1 -static SUDOKU_ATTR_RO(is_valid); -static SUDOKU_ATTR_RO(is_solved); +struct ksudoku { + struct kobject kobj; + const struct attribute_group *attr_group; + char *matrix; + atomic_t status; +}; +#define to_ksudoku(obj) container_of(obj, struct ksudoku, kobj) -/** - * sudoku_create_file - create sysfs attribute file for the given sudoku. - * @sudoku: sudoku - * @attr: sudoku attribute descriptor. - */ -int sudoku_create_file(struct sudoku *s, - const struct sudoku_attribute *attr) +struct ksudoku_attribute { + struct attribute attr; + ssize_t (*show)(struct ksudoku *s, struct ksudoku_attribute *attr, + char *buf); + ssize_t (*store)(struct ksudoku *s, struct ksudoku_attribute *attr, + const char *buf, size_t count); + bool value; +}; +#define to_ksudoku_attr(_attr) container_of(_attr, struct ksudoku_attribute, attr) + +/* + * The default show callback that is called by sysfs when ever a read + * operation happens on any attribute on ksudoku subsystem. +*/ +static ssize_t ksudoku_default_attr_show(struct kobject *kobj, + struct attribute *attr, + char *buf) { - int error = 0; + struct ksudoku_attribute *attribute; + struct ksudoku *sudoku; - if (s) { - WARN(((attr->attr.mode & S_IWUGO) && !attr->store), - "Attribute %s: write permission without 'store'\n", - attr->attr.name); - WARN(((attr->attr.mode & S_IRUGO) && !attr->show), - "Attribute %s: read permission without 'show'\n", - attr->attr.name); - error = sysfs_create_file(&s->kobj, &attr->attr); - } + attribute = to_ksudoku_attr(attr); + sudoku = to_ksudoku(kobj); - return error; + if (!attribute->show) + return -EIO; + + return attribute->show(sudoku, attribute, buf); } -EXPORT_SYMBOL_GPL(sudoku_create_file); -/* static ssize_t is_valid_show(struct kobject *kobj, struct attribute *attr, */ -/* char *buf) */ -/* { */ -/* struct sudoku_attribute *s_attr = to_sudoku_attr(attr); */ -/* struct sudoku *s = to_sudoku(kobj); */ -/* ssize_t ret = -EIO; */ +/* + * The default show callback that is called by sysfs when ever a write + * operation happens on any attribute on ksudoku subsystem. +*/ +static ssize_t ksudoku_default_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, + size_t len) +{ + struct ksudoku_attribute *attribute; + struct ksudoku *sudoku; -/* if (s_attr->show) */ -/* ret = s_attr->show(s, s_attr, buf); */ + attribute = to_ksudoku_attr(attr); + sudoku = to_ksudoku(kobj); -/* if (ret >= (ssize_t)PAGE_SIZE) { */ -/* printk("is_valid_show: %pS returned bad count\n", */ -/* s_attr->show); */ -/* } */ -/* return ret; */ -/* } */ + if (!attribute->store) + return -EIO; + + return attribute->store(sudoku, attribute, buf, len); +} + +/* + * Create a `sysfs_ops` structure in order to register + * the default IO operation handlers of ksudoku subsystem. + */ +static const struct sysfs_ops ksudoku_sysfs_ops = { + .show = ksudoku_default_attr_show, + .store = ksudoku_default_attr_store, +}; + +/* + * The release function for ksudoku. This is REQUIRED by the kernel to + * have. We free the memory held in our object here. + * + * We should free the memory here rather than the exit method of the + * module. Kernel will call this function as soon as the reference + * counter on the kobject embedded inside the ksudoku object hits + * zero. So it might happen before or after exit function. + * + * The release function is per kobject so we're going to free + * different ksudoku instances separated from eachother. + */ +static void ksudoku_release(struct kobject *kobj) +{ + struct ksudoku *s; + + s = to_ksudoku(kobj); + kfree(s); +} + +/* + * The show handler of `status` attribute. This callback will + * be called via `ksudoku_default_attr_show` which is the + * default read handler on ksudoku_type for ksudoku subsystem. + * + * Since `status` suppose to read only there would not be + * a store handler. + */ +static ssize_t status_show(struct ksudoku *s, + struct ksudoku_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d", atomic_read(&s->status)); +} + +// __ATTR_RO macro will set the `.show` member of +// `status_attribute` to `status_show` (name + _show) +static struct ksudoku_attribute status_attribute = __ATTR_RO(status); + + +static ssize_t matrix_show(struct ksudoku *s, + struct ksudoku_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s", s->matrix); +} + +static ssize_t matrix_store(struct ksudoku *s, + struct ksudoku_attribute *attr, + const char *buf, + size_t len) +{ + int status = atomic_read(&s->status); + + if (status == KSUDOKU_BUSY) + return -EBUSY; + + if (len != 81) + return -EIO; + + strncpy(s->matrix, buf, len); + return len; +} + +static struct ksudoku_attribute matrix_attribute = + __ATTR(matrix, 0664, matrix_show, matrix_store); + + +static struct attribute *ksudoku_default_attrs[] = { + &status_attribute.attr, + &matrix_attribute.attr, + NULL +}; +ATTRIBUTE_GROUPS(ksudoku_default); + + +static struct kobj_type ksudoku_type = { + .sysfs_ops = &ksudoku_sysfs_ops, + .release = ksudoku_release, + .default_groups = ksudoku_default_groups, +}; + + +static struct kset *ksudoku_set; + +static struct ksudoku *create_ksudoku(const char *name) +{ + struct ksudoku *s; + int result; + + s = kzalloc(sizeof(*s), GFP_KERNEL); + if (!s) + return NULL; + + s->kobj.kset = ksudoku_set; + + result = kobject_init_and_add(&s->kobj, &ksudoku_type, + NULL, "%s", name); + + if (result) { + kobject_put(&s->kobj); + return NULL; + } + + atomic_set(&s->status, KSUDOKU_READY); + + // Let the world now about the new registered kobj + kobject_uevent(&s->kobj, KOBJ_ADD); + return s; +} + +static void destroy_ksudoku(struct ksudoku *s) +{ + kobject_put(&s->kobj); +} static int ksudoku_init(void) { - printk(KERN_ALERT "Init ksudoku.\n"); + printk(KERN_ALERT "Init ksudoku subsystem.\n"); + + // kernel_kobj is the kobject related to /sys/kernel + ksudoku_set = kset_create_and_add("ksudoku", NULL, kernel_kobj); + + if (!ksudoku_set) + return -ENOMEM; + + printk(KERN_ALERT "Ready to register sudokus.\n"); + /* sudoku = kmalloc(sizeof (struct ksudoku), GFP_KERNEL); */ + + /* atomic_set(&sudoku->status, 0); */ + /* sudoku->attr_group = &attr_group; */ + + /* if (!sudoku) */ + /* return -ENOMEM; */ + + /* sudoku->kobj = kobject_create_and_add("ksudoku", kernel_kobj); */ + + /* if (!&sudoku->kobj) */ + /* return -ENOMEM; */ + + /* sysfs_result = sysfs_create_group(sudoku->kobj, sudoku->attr_group); */ + + /* if (sysfs_result) */ + /* kobject_put(sudoku->kobj); */ + return 0; } static void ksudoku_exit(void) { + //kobject_put(sudoku->kobj); + kset_unregister(ksudoku_set); printk(KERN_ALERT "Exit ksudoku.\n"); } diff --git a/ksudoku.h b/ksudoku.h index 1e72c41..6bede36 100644 --- a/ksudoku.h +++ b/ksudoku.h @@ -1,36 +1,22 @@ #ifndef _KSUDOKU_H_ #define _KSUDOKU_H_ + #include #include #include +#include -#define to_sudoku(obj) container_of(obj, struct sudoku, kobj) -#define to_sudoku_attr(_attr) container_of(_attr, struct sudoku_attribute, attr) - -struct sudoku; - -static ssize_t is_valid_show(struct kobject *kobj, - struct attribute *attr, - char *buf); - -static ssize_t is_valid_store(struct kobject *, - struct attribute *, - const char *, size_t); - -static ssize_t is_solved_show(struct kobject *kobj, - struct attribute *attr, - char *buf); - -static ssize_t is_solved_store(struct kobject *, - struct attribute *, - const char *, size_t); +struct ksudoku; +#define to_ksudoku(obj) container_of(obj, struct ksudoku, kobj) +#define to_ksudoku_attr(_attr) container_of(_attr, struct kobj_attribute, attr) struct sudoku_attribute { struct attribute attr; ssize_t (*show)(struct kobject *kobj, struct attribute *attr, char *buf); - ssize_t (*store)(void); + ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count); bool value; }; @@ -44,32 +30,25 @@ struct sudoku_attribute { * If "name" is specified, the uevent will contain it in * the DEVTYPE variable. */ -struct sudoku_type { - const char *name; - const struct attribute_group **groups; - int (*uevent)(struct sudoku *s, struct kobj_uevent_env *env); - char *(*devnode)(struct sudoku *s, umode_t *mode, - kuid_t *uid, kgid_t *gid); - void (*release)(struct sudoku *s); +/* struct sudoku_type { */ +/* const char *name; */ +/* const struct attribute_group **groups; */ +/* int (*uevent)(struct sudoku *s, struct kobj_uevent_env *env); */ +/* void (*release)(struct kobject *kobj); */ +/* const struct sysfs_ops *sysfs_ops; */ +/* }; */ - const struct sysfs_ops *sysfs_ops; -}; - -struct sudoku { - struct kobject kobj; - struct sudoku *parent; - const struct sudoku_type *type; +struct ksudoku { + struct kobject *kobj; + const struct attribute_group *attr_group; char matrix[81]; - -}; + atomic_t status; +} ; #define SUDOKU_ATTR_RO(_name) \ - struct sudoku_attribute sudoku_##_name = __ATTR_RO(_name) + struct kobj_attribute sudoku_##_name = __ATTR_RO(_name) #define SUDOKU_ATTR_WO(_name) \ - struct sudoku_attribute sudoku_##_name = __ATTR_WO(_name) - -extern int sudoku_create_file(struct sudoku *s, - const struct sudoku_attribute *attr); + struct kobj_attribute sudoku_##_name = __ATTR_WO(_name) #endif diff --git a/ksudoku.mod b/ksudoku.mod deleted file mode 100644 index 67785a2..0000000 --- a/ksudoku.mod +++ /dev/null @@ -1,2 +0,0 @@ -/home/lxsameer/src/linux/ksudoku/ksudoku.o -