/*
 * IO prober
 *
 * Copyright (C) 2008 <ard@kwaak.net>
 *
 *	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.
 *
 * 2008_09_20 
 *	F1rst version
 * 
 */

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/serial.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>

/*
 * Version Information
 */
#define DRIVER_VERSION "v1"
#define DRIVER_DESC "IOprober /dev/mem alternative"




struct proc_dir_entry *proc_ioprober_root;
static void *ioprober_address=0;
static int ioprober_read_address (char *page, char **start, off_t off,
			  int count, int *eof, void *data)
{
	int len = 0;
	len += sprintf(page+len, "%08lx\n", (long unsigned int) ioprober_address);  		
	return len;
}

static int ioprober_write_address(struct file *file, const char *buffer, unsigned long count, void *data)
{
	unsigned long val = simple_strtoul(buffer, 0, 16);
	ioprober_address=(void *)val;
	return count;
}
static int ioprober_read_r8 (char *page, char **start, off_t off,
			  int count, int *eof, void *vdata)
{
	int len = 0;
	u8 *where;
	u32 data;
	where=ioprober_address;
	data=*where;
	len += sprintf(page+len, "%08lx\n", (long unsigned int) data);  		
	return len;
}

static int ioprober_write_r8(struct file *file, const char *buffer, unsigned long count, void *vdata)
{
	unsigned long val = simple_strtoul(buffer, 0, 16);
	u8 *where;
	where=ioprober_address;
	*where=val;
	return count;
}
static int ioprober_read_r16 (char *page, char **start, off_t off,
			  int count, int *eof, void *vdata)
{
	int len = 0;
	u16 *where;
	u32 data;
	where=ioprober_address;
	data=*where;
	len += sprintf(page+len, "%08lx\n", (long unsigned int) data);  		
	return len;
}

static int ioprober_write_r16(struct file *file, const char *buffer, unsigned long count, void *vdata)
{
	unsigned long val = simple_strtoul(buffer, 0, 16);
	u16 *where;
	where=ioprober_address;
	*where=val;
	return count;
}
static int ioprober_read_r32 (char *page, char **start, off_t off,
			  int count, int *eof, void *vdata)
{
	int len = 0;
	u32 *where;
	u32 data;
	where=ioprober_address;
	data=*where;
	len += sprintf(page+len, "%08lx\n", (long unsigned int) data);  		
	return len;
}

static int ioprober_write_r32(struct file *file, const char *buffer, unsigned long count, void *vdata)
{
	unsigned long val = simple_strtoul(buffer, 0, 16);
	u32 *where;
	where=ioprober_address;
	*where=val;
	return count;
}

static int __init ioprober_init(void)
{
	struct proc_dir_entry *res;

	proc_ioprober_root = proc_mkdir("ioprober", 0);
	if(!proc_ioprober_root) {
		//err("failed to create ioprober directory");
		return -1;
	}
	res = create_proc_entry("r8", 0600, proc_ioprober_root);
	if (res) {
		res->read_proc = ioprober_read_r8;
		res->write_proc = ioprober_write_r8;
		res->data = NULL;
	}
	res = create_proc_entry("r16", 0600, proc_ioprober_root);
	if (res) {
		res->read_proc = ioprober_read_r16;
		res->write_proc = ioprober_write_r16;
		res->data = NULL;
	}
	res = create_proc_entry("r32", 0600, proc_ioprober_root);
	if (res) {
		res->read_proc = ioprober_read_r32;
		res->write_proc = ioprober_write_r32;
		res->data = NULL;
	}
	res = create_proc_entry("address", 0600, proc_ioprober_root);
	if (res) {
		res->read_proc = ioprober_read_address;
		res->write_proc = ioprober_write_address;
		res->data = NULL;
	}
	//info(DRIVER_DESC " " DRIVER_VERSION);
	return 0;
}

static void __exit ioprober_exit (void)
{
	remove_proc_entry("address",proc_ioprober_root);
	remove_proc_entry("r32",proc_ioprober_root);
	remove_proc_entry("r16",proc_ioprober_root);
	remove_proc_entry("r8",proc_ioprober_root);
	remove_proc_entry("ioprober",0);
}


module_init(ioprober_init);
module_exit(ioprober_exit);

MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");


