Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3e37a030 authored by Benjamin Romer's avatar Benjamin Romer Committed by Greg Kroah-Hartman
Browse files

staging: unisys: remove last remnants of proc entry code



All of the proc code using easyproc and procobjecttree support is gone,
so we can remove it from the source entirely.

Signed-off-by: default avatarBenjamin Romer <benjamin.romer@unisys.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 862cf604
Loading
Loading
Loading
Loading
+1 −2
Original line number Original line Diff line number Diff line
@@ -4,7 +4,6 @@


obj-$(CONFIG_UNISYS_VISORUTIL)	+= visorutil.o
obj-$(CONFIG_UNISYS_VISORUTIL)	+= visorutil.o


visorutil-y := charqueue.o  easyproc.o  periodic_work.o  procobjecttree.o  \
visorutil-y := charqueue.o  periodic_work.o  memregion_direct.o visorkmodutils.o
		memregion_direct.o visorkmodutils.o


ccflags-y += -Idrivers/staging/unisys/include
ccflags-y += -Idrivers/staging/unisys/include
+0 −356
Original line number Original line Diff line number Diff line
/* Copyright (C) 2010 - 2013 UNISYS CORPORATION
 * All rights reserved.
 *
 * 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, GOOD TITLE or
 * NON INFRINGEMENT.  See the GNU General Public License for more
 * details.
 */

/** @file *********************************************************************
 *
 *  Handle procfs-specific tasks.
 *  Note that this file does not know about any module-specific things, nor
 *  does it know anything about what information to reveal as part of the proc
 *  entries.  The 2 functions that take care of displaying device and
 *  driver specific information are passed as parameters to
 *  visor_easyproc_InitDriver().
 *
 *      void show_device_info(struct seq_file *seq, void *p);
 *      void show_driver_info(struct seq_file *seq);
 *
 *  The second parameter to show_device_info is actually a pointer to the
 *  device-specific info to show.  It is the context that was originally
 *  passed to visor_easyproc_InitDevice().
 *
 ******************************************************************************
 */

#include <linux/proc_fs.h>

#include "timskmod.h"
#include "easyproc.h"

#define MYDRVNAME "easyproc"



/*
 *   /proc/<ProcId>                              ProcDir
 *   /proc/<ProcId>/driver                       ProcDriverDir
 *   /proc/<ProcId>/driver/diag                  ProcDriverDiagFile
 *   /proc/<ProcId>/device                       ProcDeviceDir
 *   /proc/<ProcId>/device/0                     procDevicexDir
 *   /proc/<ProcId>/device/0/diag                procDevicexDiagFile
 */


static ssize_t proc_write_device(struct file *file, const char __user *buffer,
				 size_t count, loff_t *ppos);
static ssize_t proc_write_driver(struct file *file, const char __user *buffer,
				 size_t count, loff_t *ppos);

static struct proc_dir_entry *
	createProcDir(char *name, struct proc_dir_entry *parent)
{
	struct proc_dir_entry *p = proc_mkdir_mode(name, S_IFDIR, parent);
	return p;
}

static int seq_show_driver(struct seq_file *seq, void *offset);
static int proc_open_driver(struct inode *inode, struct file *file)
{
	return single_open(file, seq_show_driver, PDE_DATA(inode));
}
static const struct file_operations proc_fops_driver = {
	.open = proc_open_driver,
	.read = seq_read,
	.write = proc_write_driver,
	.llseek = seq_lseek,
	.release = single_release,
};

static int seq_show_device(struct seq_file *seq, void *offset);
static int seq_show_device_property(struct seq_file *seq, void *offset);
static int proc_open_device(struct inode *inode, struct file *file)
{
	return single_open(file, seq_show_device, PDE_DATA(inode));
}
static const struct file_operations proc_fops_device = {
	.open = proc_open_device,
	.read = seq_read,
	.write = proc_write_device,
	.llseek = seq_lseek,
	.release = single_release,
};
static int proc_open_device_property(struct inode *inode, struct file *file)
{
	return single_open(file, seq_show_device_property, PDE_DATA(inode));
}
static const struct file_operations proc_fops_device_property = {
	.open = proc_open_device_property,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = single_release,
};



void visor_easyproc_InitDriver(struct easyproc_driver_info *pdriver,
			       char *procId,
			       void (*show_driver_info)(struct seq_file *),
			       void (*show_device_info)(struct seq_file *,
							void *))
{
	memset(pdriver, 0, sizeof(struct easyproc_driver_info));
	pdriver->ProcId = procId;
	pdriver->Show_driver_info = show_driver_info;
	pdriver->Show_device_info = show_device_info;
	if (pdriver->ProcDir == NULL)
		pdriver->ProcDir = createProcDir(pdriver->ProcId, NULL);
	if ((pdriver->ProcDir != NULL) && (pdriver->ProcDriverDir == NULL))
		pdriver->ProcDriverDir = createProcDir("driver",
						       pdriver->ProcDir);
	if ((pdriver->ProcDir != NULL) && (pdriver->ProcDeviceDir == NULL))
		pdriver->ProcDeviceDir = createProcDir("device",
						       pdriver->ProcDir);
	if ((pdriver->ProcDriverDir != NULL) &&
	    (pdriver->ProcDriverDiagFile == NULL)) {
		pdriver->ProcDriverDiagFile =
			proc_create_data("diag", 0,
					 pdriver->ProcDriverDir,
					 &proc_fops_driver, pdriver);
	}
}
EXPORT_SYMBOL_GPL(visor_easyproc_InitDriver);



void visor_easyproc_InitDriverEx(struct easyproc_driver_info *pdriver,
				 char *procId,
				 void (*show_driver_info)(struct seq_file *),
				 void (*show_device_info)(struct seq_file *,
							  void *),
				 void (*write_driver_info)(char *buf,
							   size_t count,
							   loff_t *ppos),
				 void (*write_device_info)(char *buf,
							   size_t count,
							   loff_t *ppos,
							   void *p))
{
	visor_easyproc_InitDriver(pdriver, procId,
				  show_driver_info, show_device_info);
	pdriver->Write_driver_info = write_driver_info;
	pdriver->Write_device_info = write_device_info;
}
EXPORT_SYMBOL_GPL(visor_easyproc_InitDriverEx);



void visor_easyproc_DeInitDriver(struct easyproc_driver_info *pdriver)
{
	if (pdriver->ProcDriverDiagFile != NULL) {
		remove_proc_entry("diag", pdriver->ProcDriverDir);
		pdriver->ProcDriverDiagFile = NULL;
	}
	if (pdriver->ProcDriverDir != NULL) {
		remove_proc_entry("driver", pdriver->ProcDir);
		pdriver->ProcDriverDir = NULL;
	}
	if (pdriver->ProcDeviceDir != NULL) {
		remove_proc_entry("device", pdriver->ProcDir);
		pdriver->ProcDeviceDir = NULL;
	}
	if (pdriver->ProcDir != NULL) {
		remove_proc_entry(pdriver->ProcId, NULL);
		pdriver->ProcDir = NULL;
	}
	pdriver->ProcId = NULL;
	pdriver->Show_driver_info = NULL;
	pdriver->Show_device_info = NULL;
	pdriver->Write_driver_info = NULL;
	pdriver->Write_device_info = NULL;
}
EXPORT_SYMBOL_GPL(visor_easyproc_DeInitDriver);



void visor_easyproc_InitDevice(struct easyproc_driver_info *pdriver,
			       struct easyproc_device_info *p, int devno,
			       void *devdata)
{
	if ((pdriver->ProcDeviceDir != NULL) && (p->procDevicexDir == NULL)) {
		char s[29];

		sprintf(s, "%d", devno);
		p->procDevicexDir = createProcDir(s, pdriver->ProcDeviceDir);
		p->devno = devno;
	}
	p->devdata = devdata;
	p->pdriver = pdriver;
	p->devno = devno;
	if ((p->procDevicexDir != NULL) && (p->procDevicexDiagFile == NULL)) {
		p->procDevicexDiagFile =
			proc_create_data("diag", 0, p->procDevicexDir,
					 &proc_fops_device, p);
	}
	memset(&(p->device_property_info[0]), 0,
	       sizeof(p->device_property_info));
}
EXPORT_SYMBOL_GPL(visor_easyproc_InitDevice);



void visor_easyproc_CreateDeviceProperty(struct easyproc_device_info *p,
					 void (*show_property_info)
					 (struct seq_file *, void *),
					 char *property_name)
{
	size_t i;
	struct easyproc_device_property_info *px = NULL;

	if (p->procDevicexDir == NULL)
		return;
	for (i = 0; i < ARRAY_SIZE(p->device_property_info); i++) {
		if (p->device_property_info[i].procEntry == NULL) {
			px = &(p->device_property_info[i]);
			break;
		}
	}
	if (!px)
		return;

	px->devdata = p->devdata;
	px->pdriver = p->pdriver;
	px->procEntry = proc_create_data(property_name, 0, p->procDevicexDir,
					 &proc_fops_device_property, px);
	if (strlen(property_name)+1 > sizeof(px->property_name)) {
		return;
	}
	strcpy(px->property_name, property_name);
	if (px->procEntry == NULL) {
		return;
	}
	px->show_device_property_info = show_property_info;
}
EXPORT_SYMBOL_GPL(visor_easyproc_CreateDeviceProperty);



void visor_easyproc_DeInitDevice(struct easyproc_driver_info *pdriver,
				 struct easyproc_device_info *p, int devno)
{
	size_t i;

	for (i = 0; i < ARRAY_SIZE(p->device_property_info); i++) {
		if (p->device_property_info[i].procEntry != NULL) {
			struct easyproc_device_property_info *px =
				&(p->device_property_info[i]);
			remove_proc_entry(px->property_name, p->procDevicexDir);
			px->procEntry = NULL;
		}
	}
	if (p->procDevicexDiagFile != NULL) {
		remove_proc_entry("diag", p->procDevicexDir);
		p->procDevicexDiagFile = NULL;
	}
	if (p->procDevicexDir != NULL) {
		char s[29];

		sprintf(s, "%d", devno);
		remove_proc_entry(s, pdriver->ProcDeviceDir);
		p->procDevicexDir = NULL;
	}
	p->devdata = NULL;
	p->pdriver = NULL;
}
EXPORT_SYMBOL_GPL(visor_easyproc_DeInitDevice);



static int seq_show_driver(struct seq_file *seq, void *offset)
{
	struct easyproc_driver_info *p =
		(struct easyproc_driver_info *)(seq->private);
	if (!p)
		return 0;
	(*(p->Show_driver_info))(seq);
	return 0;
}



static int seq_show_device(struct seq_file *seq, void *offset)
{
	struct easyproc_device_info *p =
		(struct easyproc_device_info *)(seq->private);
	if ((!p) || (!(p->pdriver)))
		return 0;
	(*(p->pdriver->Show_device_info))(seq, p->devdata);
	return 0;
}



static int seq_show_device_property(struct seq_file *seq, void *offset)
{
	struct easyproc_device_property_info *p =
		(struct easyproc_device_property_info *)(seq->private);
	if ((!p) || (!(p->show_device_property_info)))
		return 0;
	(*(p->show_device_property_info))(seq, p->devdata);
	return 0;
}



static ssize_t proc_write_driver(struct file *file, const char __user *buffer,
				 size_t count, loff_t *ppos)
{
	struct seq_file *seq = (struct seq_file *)file->private_data;
	struct easyproc_driver_info *p = NULL;
	char local_buf[256];

	if (seq == NULL)
		return 0;
	p = (struct easyproc_driver_info *)(seq->private);
	if ((!p) || (!(p->Write_driver_info)))
		return 0;
	if (count >= sizeof(local_buf))
		return -ENOMEM;
	if (copy_from_user(local_buf, buffer, count))
		return -EFAULT;
	local_buf[count] = '\0';  /* be friendly */
	(*(p->Write_driver_info))(local_buf, count, ppos);
	return count;
}



static ssize_t proc_write_device(struct file *file, const char __user *buffer,
				 size_t count, loff_t *ppos)
{
	struct seq_file *seq = (struct seq_file *)file->private_data;
	struct easyproc_device_info *p = NULL;
	char local_buf[256];

	if (seq == NULL)
		return 0;
	p = (struct easyproc_device_info *)(seq->private);
	if ((!p) || (!(p->pdriver)) || (!(p->pdriver->Write_device_info)))
		return 0;
	if (count >= sizeof(local_buf))
		return -ENOMEM;
	if (copy_from_user(local_buf, buffer, count))
		return -EFAULT;
	local_buf[count] = '\0';  /* be friendly */
	(*(p->pdriver->Write_device_info))(local_buf, count, ppos, p->devdata);
	return count;
}
+0 −92
Original line number Original line Diff line number Diff line
/* easyproc.h
 *
 * Copyright (C) 2010 - 2013 UNISYS CORPORATION
 * All rights reserved.
 *
 * 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, GOOD TITLE or
 * NON INFRINGEMENT.  See the GNU General Public License for more
 * details.
 */

/** @file *********************************************************************
 *
 *  This describes the interfaces necessary for a simple /proc file
 *  implementation for a driver.
 *
 ******************************************************************************
 */

#ifndef __EASYPROC_H__
#define __EASYPROC_H__

#include "timskmod.h"


struct easyproc_driver_info {
	struct proc_dir_entry *ProcDir;
	struct proc_dir_entry *ProcDriverDir;
	struct proc_dir_entry *ProcDriverDiagFile;
	struct proc_dir_entry *ProcDeviceDir;
	char *ProcId;
	void (*Show_device_info)(struct seq_file *seq, void *p);
	void (*Show_driver_info)(struct seq_file *seq);
	void (*Write_device_info)(char *buf, size_t count,
				  loff_t *ppos, void *p);
	void (*Write_driver_info)(char *buf, size_t count, loff_t *ppos);
};

/* property is a file under /proc/<x>/device/<x>/<property_name> */
struct easyproc_device_property_info {
	char property_name[25];
	struct proc_dir_entry *procEntry;
	struct easyproc_driver_info *pdriver;
	void *devdata;
	void (*show_device_property_info)(struct seq_file *seq, void *p);
};

struct easyproc_device_info {
	struct proc_dir_entry *procDevicexDir;
	struct proc_dir_entry *procDevicexDiagFile;
	struct easyproc_driver_info *pdriver;
	void *devdata;
	int devno;
	/*  allow for a number of custom properties for each device: */
	struct easyproc_device_property_info device_property_info[10];
};

void visor_easyproc_InitDevice(struct easyproc_driver_info *pdriver,
			       struct easyproc_device_info *p, int devno,
			       void *devdata);
void visor_easyproc_DeInitDevice(struct easyproc_driver_info *pdriver,
				 struct easyproc_device_info *p, int devno);
void visor_easyproc_InitDriver(struct easyproc_driver_info *pdriver,
			       char *procId,
			       void (*show_driver_info)(struct seq_file *),
			       void (*show_device_info)(struct seq_file *,
							void *));
void visor_easyproc_InitDriverEx(struct easyproc_driver_info *pdriver,
				 char *procId,
				 void (*show_driver_info)(struct seq_file *),
				 void (*show_device_info)(struct seq_file *,
							  void *),
				 void (*Write_driver_info)(char *buf,
							   size_t count,
							   loff_t *ppos),
				 void (*Write_device_info)(char *buf,
							   size_t count,
							   loff_t *ppos,
							   void *p));
void visor_easyproc_DeInitDriver(struct easyproc_driver_info *pdriver);
void visor_easyproc_CreateDeviceProperty(struct easyproc_device_info *p,
					 void (*show_property_info)
					 (struct seq_file *, void *),
					 char *property_name);

#endif
+0 −335
Original line number Original line Diff line number Diff line
/* procobjecttree.c
 *
 * Copyright (C) 2010 - 2013 UNISYS CORPORATION
 * All rights reserved.
 *
 * 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, GOOD TITLE or
 * NON INFRINGEMENT.  See the GNU General Public License for more
 * details.
 */

#include "procobjecttree.h"

#define MYDRVNAME "procobjecttree"



/** This is context info that we stash in each /proc file entry, which we
 *  need in order to call the callback function that supplies the /proc read
 *  info for that file.
 */
struct proc_dir_entry_context {
	void (*show_property)(struct seq_file *, void *, int);
	MYPROCOBJECT *procObject;
	int propertyIndex;

};

/** This describes the attributes of a tree rooted at
 *  <procDirRoot>/<name[0]>/<name[1]>/...
 *  Properties for each object of this type will be located under
 *  <procDirRoot>/<name[0]>/<name[1]>/.../<objectName>/<propertyName>.
 */
struct MYPROCTYPE_Tag {
	const char **name;  /**< node names for this type, ending with NULL */
	int nNames;         /**< num of node names in <name> */

	/** root dir for this type tree in /proc */
	struct proc_dir_entry *procDirRoot;

	struct proc_dir_entry **procDirs;  /**< for each node in <name> */

	/** bottom dir where objects will be rooted; i.e., this is
	 *  <procDirRoot>/<name[0]>/<name[1]>/.../, which is the same as the
	 *  last entry in the <procDirs> array. */
	struct proc_dir_entry *procDir;

	/** name for each property that objects of this type can have */
	const char **propertyNames;

	int nProperties;       /**< num of names in <propertyNames> */

	/** Call this, passing MYPROCOBJECT.context and the property index
	 *  whenever someone reads the proc entry */
	void (*show_property)(struct seq_file *, void *, int);
};



struct MYPROCOBJECT_Tag {
	MYPROCTYPE *type;

	/** This is the name of the dir node in /proc under which the
	 *  properties of this object will appear as files. */
	char *name;

	int namesize;   /**< number of bytes allocated for name */
	void *context;  /**< passed to MYPROCTYPE.show_property */

	/** <type.procDirRoot>/<type.name[0]>/<type.name[1]>/.../<name> */
	struct proc_dir_entry *procDir;

	/** a proc dir entry for each of the properties of the object;
	 *  properties are identified in MYPROCTYPE.propertyNames, so each of
	 *  the <procDirProperties> describes a single file like
	 *  <type.procDirRoot>/<type.name[0]>/<type.name[1]>/...
	 *           /<name>/<propertyName>
	 */
	struct proc_dir_entry **procDirProperties;

	/** this is a holding area for the context information that is needed
	 *  to run the /proc callback function */
	struct proc_dir_entry_context *procDirPropertyContexts;
};



static struct proc_dir_entry *
createProcDir(const char *name, struct proc_dir_entry *parent)
{
	struct proc_dir_entry *p = proc_mkdir_mode(name, S_IFDIR, parent);

	return p;
}

static struct proc_dir_entry *
createProcFile(const char *name, struct proc_dir_entry *parent,
	       const struct file_operations *fops, void *data)
{
	struct proc_dir_entry *p = proc_create_data(name, 0, parent,
						    fops, data);
	return p;
}

static int seq_show(struct seq_file *seq, void *offset);
static int proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, seq_show, PDE_DATA(inode));
}

static const struct file_operations proc_fops = {
	.open = proc_open,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = single_release,
};



MYPROCTYPE *visor_proc_CreateType(struct proc_dir_entry *procDirRoot,
				  const char **name,
				  const char **propertyNames,
				  void (*show_property)(struct seq_file *,
							void *, int))
{
	int i = 0;
	MYPROCTYPE *rc = NULL, *type = NULL;
	struct proc_dir_entry *parent = NULL;

	if (procDirRoot == NULL)
		goto Away;

	if (name == NULL || name[0] == NULL)
		goto Away;

	type = kzalloc(sizeof(MYPROCTYPE), GFP_KERNEL | __GFP_NORETRY);
	if (type == NULL)
		goto Away;

	type->name = name;
	type->propertyNames = propertyNames;
	type->nProperties = 0;
	type->nNames = 0;
	type->show_property = show_property;
	type->procDirRoot = procDirRoot;
	if (type->propertyNames != NULL)
		while (type->propertyNames[type->nProperties] != NULL)
			type->nProperties++;
	while (type->name[type->nNames] != NULL)
		type->nNames++;
	type->procDirs = kcalloc((type->nNames + 1),
				 sizeof(struct proc_dir_entry *),
				 GFP_KERNEL | __GFP_NORETRY);
	if (type->procDirs == NULL)
		goto Away;
	parent = procDirRoot;
	for (i = 0; i < type->nNames; i++) {
		type->procDirs[i] = createProcDir(type->name[i], parent);
		if (type->procDirs[i] == NULL) {
			rc = NULL;
			goto Away;
		}
		parent = type->procDirs[i];
	}
	type->procDir = type->procDirs[type->nNames-1];
	rc = type;
Away:
	if (rc == NULL) {
		if (type != NULL) {
			visor_proc_DestroyType(type);
			type = NULL;
		}
	}
	return rc;
}
EXPORT_SYMBOL_GPL(visor_proc_CreateType);



void visor_proc_DestroyType(MYPROCTYPE *type)
{
	if (type == NULL)
		return;
	if (type->procDirs != NULL) {
		int i = type->nNames-1;

		while (i >= 0) {
			if (type->procDirs[i] != NULL) {
				struct proc_dir_entry *parent = NULL;

				if (i == 0)
					parent = type->procDirRoot;
				else
					parent = type->procDirs[i-1];
				remove_proc_entry(type->name[i], parent);
			}
			i--;
		}
		kfree(type->procDirs);
		type->procDirs = NULL;
	}
	kfree(type);
}
EXPORT_SYMBOL_GPL(visor_proc_DestroyType);



MYPROCOBJECT *visor_proc_CreateObject(MYPROCTYPE *type,
				      const char *name, void *context)
{
	MYPROCOBJECT *obj = NULL, *rc = NULL;
	int i = 0;

	if (type == NULL)
		goto Away;

	obj = kzalloc(sizeof(MYPROCOBJECT), GFP_KERNEL | __GFP_NORETRY);
	if (obj == NULL)
		goto Away;

	obj->type = type;
	obj->context = context;
	if (name == NULL) {
		obj->name = NULL;
		obj->procDir = type->procDir;
	} else {
		obj->namesize = strlen(name)+1;
		obj->name = kmalloc(obj->namesize, GFP_KERNEL | __GFP_NORETRY);
		if (obj->name == NULL) {
			obj->namesize = 0;
			goto Away;
		}
		strcpy(obj->name, name);
		obj->procDir = createProcDir(obj->name, type->procDir);
		if (obj->procDir == NULL)
			goto Away;
	}
	obj->procDirPropertyContexts =
		kcalloc((type->nProperties + 1),
			sizeof(struct proc_dir_entry_context),
			GFP_KERNEL | __GFP_NORETRY);
	if (obj->procDirPropertyContexts == NULL)
		goto Away;
	obj->procDirProperties = kcalloc((type->nProperties + 1),
					 sizeof(struct proc_dir_entry *),
					 GFP_KERNEL | __GFP_NORETRY);
	if (obj->procDirProperties == NULL)
		goto Away;
	for (i = 0; i < type->nProperties; i++) {
		obj->procDirPropertyContexts[i].procObject = obj;
		obj->procDirPropertyContexts[i].propertyIndex = i;
		obj->procDirPropertyContexts[i].show_property =
			type->show_property;
		if (type->propertyNames[i][0] != '\0') {
			/* only create properties that have names */
			obj->procDirProperties[i] =
				createProcFile(type->propertyNames[i],
					obj->procDir, &proc_fops,
					&obj->procDirPropertyContexts[i]);
			if (obj->procDirProperties[i] == NULL) {
				rc = NULL;
				goto Away;
			}
		}
	}
	rc = obj;
Away:
	if (rc == NULL) {
		if (obj != NULL) {
			visor_proc_DestroyObject(obj);
			obj = NULL;
		}
	}
	return rc;
}
EXPORT_SYMBOL_GPL(visor_proc_CreateObject);



void visor_proc_DestroyObject(MYPROCOBJECT *obj)
{
	MYPROCTYPE *type = NULL;

	if (obj == NULL)
		return;
	type = obj->type;
	if (type == NULL)
		return;
	if (obj->procDirProperties != NULL) {
		int i = 0;

		for (i = 0; i < type->nProperties; i++) {
			if (obj->procDirProperties[i] != NULL) {
				remove_proc_entry(type->propertyNames[i],
						  obj->procDir);
				obj->procDirProperties[i] = NULL;
			}
		}
		kfree(obj->procDirProperties);
		obj->procDirProperties = NULL;
	}

	kfree(obj->procDirPropertyContexts);
	obj->procDirPropertyContexts = NULL;

	if (obj->procDir != NULL) {
		if (obj->name != NULL)
			remove_proc_entry(obj->name, type->procDir);
		obj->procDir = NULL;
	}

	kfree(obj->name);
	obj->name = NULL;
	kfree(obj);
}
EXPORT_SYMBOL_GPL(visor_proc_DestroyObject);



static int seq_show(struct seq_file *seq, void *offset)
{
	struct proc_dir_entry_context *ctx = seq->private;

	if (ctx == NULL)
		return 0;
	(*ctx->show_property)(seq, ctx->procObject->context,
			      ctx->propertyIndex);
	return 0;
}