/*
 * pat.c - an in-kernel representation of myself.
 *
 * Copyright (c) 2002 Patrick Mochel
 *                    Open Source Development Lab
 * 
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 * Compiled with

CFLAGS = -Wall -O2 -fomit-frame-pointer -DMODULE -D__KERNEL__
IDIR = /home/mochel/src/kernel/devel/linux-2.5/include

pat.o::pat.c
        $(CC) $(CFLAGS) -I$(IDIR) -c -o $@ $<
 */

#include <linux/module.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/stat.h>
#include <linux/err.h>
#include <linux/driverfs_fs.h>

struct simple_attribute {
	struct attribute	attr;
	ssize_t (*show)(char * buf, size_t count, loff_t off);
};

#define SIMPLE_ATTR(_name,_mode,_show) \
struct simple_attribute sattr_##_name = { 		\
	.attr = {.name = __stringify(_name), .mode = _mode },	\
	.show	= _show,				\
};


static char     * who = "myself";
static char     * what = "working";
static char     * when = "not for long";
static char     * where = "office";
static char     * why = "catching up";
static char     * how = "hungover";
static u32      dollars = 6;
static u32      cents = 89;
static char     * beverage = "coffee";
static int      bev_size = 12;
static char	* music = "Radiohead";

#define to_simple_attr(_attr) container_of(_attr,struct simple_attribute,attr)


/* driverfs ops for displaying my attributes */

static int pat_attr_show(struct driver_dir_entry * dir, struct attribute * attr,
			 char * buf, size_t count, loff_t off)
{
	struct simple_attribute * sattr = to_simple_attr(attr);
	if (sattr->show)
		return sattr->show(buf,count,off);
	return 0;
}

static struct driverfs_ops pat_attr_ops = {
	.show	pat_attr_show,
};

static struct driver_dir_entry pat_dir = {
	.name	= "pat",
	.mode	= (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO),
	.ops	= &pat_attr_ops,
};


/* exporting my attributes */

static ssize_t show_who(char * buf, size_t count, loff_t off)
{
	return off ? 0 : snprintf(buf,50,"%s\n",who);
}

static SIMPLE_ATTR(who,0444,show_who);


static ssize_t show_what(char * buf, size_t count, loff_t off)
{
	return off ? 0 : snprintf(buf,50,"%s\n",what);
}

static SIMPLE_ATTR(what,0444,show_what);


static ssize_t show_when(char * buf, size_t count, loff_t off)
{
	return off ? 0 : snprintf(buf,50,"%s\n",when);
}

static SIMPLE_ATTR(when,0444,show_when);


static ssize_t show_where(char * buf, size_t count, loff_t off)
{
	return off ? 0 : snprintf(buf,50,"%s\n",where);
}

static SIMPLE_ATTR(where,0444,show_where);


static ssize_t show_why(char * buf, size_t count, loff_t off)
{
	return off ? 0 : snprintf(buf,50,"%s\n",why);
}

static SIMPLE_ATTR(why,0444,show_why);


static ssize_t show_how(char * buf, size_t count, loff_t off)
{
	return off ? 0 : snprintf(buf,50,"%s\n",how);
}

static SIMPLE_ATTR(how,0444,show_how);


static ssize_t show_cash(char * buf, size_t count, loff_t off)
{
	return off ? 0 : snprintf(buf,50,"%u.%u\n",dollars,cents);
}

static SIMPLE_ATTR(cash,0444,show_cash);


static ssize_t show_beverage(char * buf, size_t count, loff_t off)
{
	return off ? 0 : snprintf(buf,50,"%s\n",beverage);
}

static SIMPLE_ATTR(beverage,0444,show_beverage);


static ssize_t show_bev_size(char * buf, size_t count, loff_t off)
{
	return off ? 0 : snprintf(buf,50,"%u\n",bev_size);
}

static SIMPLE_ATTR(bev_size,0444,show_bev_size);


static ssize_t show_music(char * buf, size_t count, loff_t off)
{
	return off ? 0 : snprintf(buf,50,"%s\n",music);
}

static SIMPLE_ATTR(music,0444,show_music);


static struct simple_attribute * pat_attrs[] = {
	&sattr_who,
	&sattr_what,
	&sattr_when,
	&sattr_where,
	&sattr_why,
	&sattr_how,
	&sattr_cash,
	&sattr_beverage,
	&sattr_bev_size,
	&sattr_music,
	NULL,
};

static int populate_dir(void)
{
	struct simple_attribute * attr;
	int i;
	int error = 0;
	
	for (i = 0; (attr = pat_attrs[i]); i++) {
		if ((error = driverfs_create_file(&attr->attr,&pat_dir)))
			break;
	}
	return error;
}

static int __init pat_init(void)
{
	driverfs_create_dir(&pat_dir,NULL);
	return populate_dir();
}

static void __exit pat_exit(void)
{
	driverfs_remove_dir(&pat_dir);
}

subsys_initcall(pat_init);
module_exit(pat_exit);