/******************************************************************************
*                                                                             *
*   Copyright 2005 University of Cambridge Computer Laboratory.               *
*                                                                             *
*   This file is part of Nprobe.                                              *
*                                                                             *
*   Nprobe 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.                                       *
*                                                                             *
*   Nprobe 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 Nprobe; if not, write to the Free Software                     *
*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *
*                                                                             *
******************************************************************************/


#define __NO_VERSION__   // keep linker happy

#include <linux/miscdevice.h>
#include <linux/proc_fs.h>
#include <linux/module.h>
#include <linux/config.h>

#include "probe.h"


/************************************************************************/

struct proc_dir_entry *nprobe_proc_entry;
int nprobe_init_proc( void );



int nprobe_read_proc(char *page, char **start,
		     off_t off, int count, int *eof, void *data);

int nprobe_write_proc(struct file *file, const char *buffer, 
		      unsigned long count, void *data);

int nprobe_init_proc( void )
{
  if (( nprobe_proc_entry = 
	create_proc_entry("nprobe", S_IRUGO | S_IWUSR, NULL)) != NULL)
    {
      nprobe_proc_entry->owner = THIS_MODULE;

      nprobe_proc_entry->read_proc  = nprobe_read_proc;
      nprobe_proc_entry->write_proc = nprobe_write_proc;


      //nprobe_proc_entry->proc_fops->open =  nprobe_open_proc;
      //nprobe_proc_entry->proc_fops->release =  nprobe_close_proc;

    }
  else
    {
      printk(KERN_ERR "NPROBE: unable to register /proc/nprobe\n");
      return -1;
    }

  return 0;
}

void nprobe_cleanup_proc( void )
{
  remove_proc_entry("nprobe", NULL );
}

int nprobe_read_proc(
    char *message, 
    char **start_x, off_t off_x, int coutn_x, int *eof_x, void *data_x) 
{
  int i;  
  char temp[128];
  unsigned long tous_tot=0;
  unsigned long frus_tot=0;

  /* We use put_user to copy the string from the kernel's memory segment
   * to the memory segment of the process that called us. get_user, BTW, is
   * used for the reverse. */
  sprintf(message, "nprobe: 0x%p %d %d %d\n",
	  np, nprobe_maxdev, FIFO_SIZE, np->num_bufs);

  for(i=0;i<US_CHANNELS;i++)
    {
      int tous_delta = np->x[i].tous_in - np->x[i].tous_out;
      int frus_delta = np->x[i].frus_in - np->x[i].frus_out;
      sprintf(temp,"%d : tous %d,%d : frus %d,%d : (%d %d)\n",
	      i,
	      np->x[i].tous_in, np->x[i].tous_out,
	      np->x[i].frus_in, np->x[i].frus_out,
	      tous_delta, frus_delta
	      );
      strcat(message, temp);
      
      tous_tot+=tous_delta;
      frus_tot+=frus_delta;
    }

  sprintf(temp,"X : tous_tot %lu, frus_tot %lu,  tot %lu\n",
	  tous_tot, frus_tot, tous_tot + frus_tot );

  strcat(message, temp);

  sprintf(temp,"X : %d skb_alloc's failed. Low water mark since last fail is %d\n",
	  np->alloc_failed_cnt, np->alloc_low_water);

  strcat(message, temp);

  return strlen(message);  /* Return the number of bytes "read" */
}



int nprobe_write_proc(struct file *file, const char __user *buffer, 
		      unsigned long count, void *data)
{
  char in[256];
  // writing to proc file causes a FIFO reset

  if( count >= sizeof(in) )
    {
      printk("NPROBE: proc input message too big. Ignoren");
      return count;
    }
    
  /* XXX should be copy_from_user */
  strncpy( in, buffer, count );
  in[count] = 0;

  printk("NPROBE: proc input called, length %ld, string XXX%sXXX\n",
	 count, in);

  //  reset_fifo();  NOT USED ANYMORE??

  //  hack_page_range( PAGE_OFFSET , (max_mapnr*PAGE_SIZE), 1 );

  hack_page_range( PAGE_OFFSET , ((1<<30)-PAGE_SIZE), 1 );

  //  hack_page_range( np , sizeof( np_t ), 1 );


  np->alloc_failed_cnt = 0;
  np->alloc_low_water = FIFO_SIZE;

  return count; // infinite sink


}


/************************************************************************/
