/*
 * rk_procfs.c (for Linux):
 *	implements the interface for procfs.
 *	shows the information on resource sets and reserves.
 *	
 * Copyright (C) 2000 TimeSys Corporation
 *
 * This is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * This file is derived from software distributed under the following terms:
 *
 * Real-Time and Multimedia Systems Laboratory
 * Copyright (c) 2000 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Real-Time and Multimedia Systems Laboratory
 *  Attn: Prof. Raj Rajkumar
 *  Electrical and Computer Engineering, and Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 *  or via email to raj@ece.cmu.edu
 * 
 * any improvements or extensions that they make and grant Carnegie Mellon
 * the rights to redistribute these changes.
 */
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>

#include <rk/rk_linux.h>
#include <rk/rk.h>

static struct proc_dir_entry *proc_rk_dir;
struct proc_process_list {
    struct list_head proc_process_list;
    struct proc_dir_entry *proc_dir_entry;
};

struct proc_process_list rk_process_list;

static int
proc_rk_status_read(char *page, char **start, off_t off,
		    int count, int *eof, void *data)
{
    char *p = page;
    extern int cpu_reserve_status_proc(char *);
    extern int net_reserve_status_proc(char *);
    extern int rcv_net_reserve_status_proc(char *);

    p += cpu_reserve_status_proc(p);
    p += net_reserve_status_proc(p);
    p += rcv_net_reserve_status_proc(p);

    return (p - page);		/* return the number of chars */
}

static int
proc_rs_status_read(char *page, char **start, off_t off,
		    int count, int *eof, void *data)
{
    char *p = page;
    extern int resource_set_status_proc(char *);

    p += resource_set_status_proc(p);

    return (p - page);		/* return the number of chars */
}

__initfunc(void rk_proc_init(void))
{
    struct proc_dir_entry *proc_rk_status;

    proc_rk_dir = create_proc_entry("rk", S_IFDIR, 0);

    proc_rk_status =
	create_proc_entry("status", S_IFREG | S_IRUGO, proc_rk_dir);
    proc_rk_status->read_proc = proc_rk_status_read;

    proc_rk_status =
	create_proc_entry("resource_set", S_IFREG | S_IRUGO, proc_rk_dir);
    proc_rk_status->read_proc = proc_rs_status_read;

    INIT_LIST_HEAD(&rk_process_list.proc_process_list);
}

void rk_proc_rs_create(rk_resource_set_t rs)
{
    char buf[16];

    sprintf(buf, "%x", (unsigned int) rs);
    rs->rs_proc_dir = create_proc_entry(buf, S_IFDIR, proc_rk_dir);
}

void rk_proc_rs_destroy(rk_resource_set_t rs)
{
    char buf[16];

    sprintf(buf, "%x", (unsigned int) rs);
    remove_proc_entry(buf, proc_rk_dir);
}

static int
proc_rsv_status_read(char *page, char **start, off_t off,
		     int count, int *eof, void *data)
{
    rk_reserve_t rsv = (rk_reserve_t) data;
    return rsv->rsv_ops->read_proc(rsv, page);
}

void rk_proc_cleanup(void)
{
    remove_proc_entry("status", proc_rk_dir);
    remove_proc_entry("resource_set", proc_rk_dir);
    remove_proc_entry("rk", &proc_root);
    INIT_LIST_HEAD(&rk_process_list.proc_process_list);
}

void rk_proc_reserve_create(rk_reserve_t rsv)
{
    rk_resource_set_t rs = rsv->rsv_rs;
    char buf[16];

#ifdef	DEBUG_RK
    printk("rk_proc_reserve_create: rs(0x%x) rsv(0x%x) type(0x%x)\n",
	   (int) rs, (int) rsv, (int) rsv->rsv_type);
#endif

    switch (rsv->rsv_type) {
    case RSV_CPU:
	sprintf(buf, "cpu");
	break;
    case RSV_NET:
	sprintf(buf, "network");
	break;
    case RSV_RCV:
      sprintf(buf, "rcv_net");
      break;
    default:
	sprintf(buf, "%x", (unsigned int) rsv);
	break;
    }

    rsv->rsv_proc_entry = create_proc_entry(buf, S_IFREG | S_IRUGO,
					    rs->rs_proc_dir);

    rsv->rsv_proc_entry->read_proc = proc_rsv_status_read;
    rsv->rsv_proc_entry->data = rsv;
}

void rk_proc_reserve_destroy(rk_reserve_t rsv)
{
    rk_resource_set_t rs = rsv->rsv_rs;
    char buf[16];

#ifdef	DEBUG_RK
    printk("rk_proc_reserve_destroy: rs(0x%x) rsv(0x%x) type(0x%x)\n",
	   (int) rs, (int) rsv, (int) rsv->rsv_type);
#endif
    switch (rsv->rsv_type) {
    case RSV_CPU:
	sprintf(buf, "cpu");
	break;
    case RSV_NET:
      sprintf(buf, "network");
      break;
    case RSV_RCV:
      sprintf(buf, "rcv_net");
      break;
    default:
	sprintf(buf, "%x", (unsigned int) rsv);
	break;
    }

    remove_proc_entry(buf, rs->rs_proc_dir);
}

static int
proc_process_status_read(char *page, char **start, off_t off,
			 int count, int *eof, void *data)
{
    struct resource_set_list *list, *rs_list;
    struct task_struct *tsk = data;
    struct list_head *ptr;
    char *p = page;
    struct rk_resource_set *rk_resource_set;


#ifdef APPLE_DEBUG
    printk("proc_status_read pid = %d \n", tsk->pid);
    p += sprintf(p, "test\n");
#endif				/* APPLE_DEBUG */

    list = &(tsk->rs_list);
    for (ptr = (&list->resource_set_list)->next;
	 ptr != (&list->resource_set_list)->next; ptr = ptr->next) {
	/* get the resource_set_list entry */
	rs_list =
	    list_entry(ptr, struct resource_set_list, resource_set_list);
	rk_resource_set = rs_list->rk_resource_set;
	printk("read %x \n", (unsigned int) rk_resource_set);

    }
    printk("proc_status_read: done\n");
    return (p - page);
}

void rk_proc_process_create(pid_t pid)
{
    struct proc_process_list *p;
    struct task_struct *tsk;
    char buf[16];

#ifdef	DEBUG_RK
    printk("rk_proc_process_create: pid(%d)\n", pid);
#endif

    sprintf(buf, "p_%d", pid);

    p = malloc(sizeof(struct proc_process_list));
    bzero(p, sizeof(struct proc_process_list));
    p->proc_dir_entry = create_proc_entry(buf, S_IFREG | S_IRUGO,
					  proc_rk_dir);

    list_add(&p->proc_process_list, &rk_process_list.proc_process_list);
    p->proc_dir_entry->read_proc = proc_process_status_read;
    tsk = __rk_find_process_by_pid(pid);
    p->proc_dir_entry->data = tsk;
}

void rk_proc_process_destroy(pid_t pid)
{
    char buf[16];

#ifdef	DEBUG_RK
    printk("rk_proc_reserve_destroy: pid(%d) \n", pid);
#endif
    sprintf(buf, "p_%d", pid);
    remove_proc_entry(buf, proc_rk_dir);
}
