staging: visorutil driver to provide common functionality to other s-Par drivers
authorKen Cox <jkc@redhat.com>
Tue, 4 Mar 2014 13:58:05 +0000 (07:58 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 5 Mar 2014 00:52:12 +0000 (16:52 -0800)
The visorutil module is a support library required by all other s-Par
driver modules. Among its features it abstracts reading, writing, and
manipulating a block of memory.

Signed-off-by: Ken Cox <jkc@redhat.com>
Cc: Ben Romer <sparmaintainer@unisys.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
20 files changed:
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/unisys/Kconfig [new file with mode: 0644]
drivers/staging/unisys/Makefile [new file with mode: 0644]
drivers/staging/unisys/include/periodic_work.h [new file with mode: 0644]
drivers/staging/unisys/include/procobjecttree.h [new file with mode: 0644]
drivers/staging/unisys/include/timskmod.h [new file with mode: 0644]
drivers/staging/unisys/include/timskmodutils.h [new file with mode: 0644]
drivers/staging/unisys/include/uniklog.h [new file with mode: 0644]
drivers/staging/unisys/visorutil/Kconfig [new file with mode: 0644]
drivers/staging/unisys/visorutil/Makefile [new file with mode: 0644]
drivers/staging/unisys/visorutil/charqueue.c [new file with mode: 0644]
drivers/staging/unisys/visorutil/charqueue.h [new file with mode: 0644]
drivers/staging/unisys/visorutil/easyproc.c [new file with mode: 0644]
drivers/staging/unisys/visorutil/easyproc.h [new file with mode: 0644]
drivers/staging/unisys/visorutil/memregion.h [new file with mode: 0644]
drivers/staging/unisys/visorutil/memregion_direct.c [new file with mode: 0644]
drivers/staging/unisys/visorutil/periodic_work.c [new file with mode: 0644]
drivers/staging/unisys/visorutil/procobjecttree.c [new file with mode: 0644]
drivers/staging/unisys/visorutil/visorkmodutils.c [new file with mode: 0644]

index d729978cc6e4acf2ca0be0a1069d42226e1939df..47cf175430082c792424fdd1fbf52b353279f60b 100644 (file)
@@ -144,4 +144,6 @@ source "drivers/staging/gs_fpgaboot/Kconfig"
 
 source "drivers/staging/nokia_h4p/Kconfig"
 
+source "drivers/staging/unisys/Kconfig"
+
 endif # STAGING
index 9eb4e8a7d13345b1963b264b88af2912deccde72..d12f6189db46ac8773923941d2ad68fd93ee9a17 100644 (file)
@@ -64,3 +64,4 @@ obj-$(CONFIG_DGAP)                    += dgap/
 obj-$(CONFIG_MTD_SPINAND_MT29F)        += mt29f_spinand/
 obj-$(CONFIG_GS_FPGABOOT)      += gs_fpgaboot/
 obj-$(CONFIG_BT_NOKIA_H4P)     += nokia_h4p/
+obj-$(CONFIG_UNISYSSPAR)       += unisys/
diff --git a/drivers/staging/unisys/Kconfig b/drivers/staging/unisys/Kconfig
new file mode 100644 (file)
index 0000000..60bbca0
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Unisys SPAR driver configuration
+#
+menuconfig UNISYSSPAR
+       bool "Unisys SPAR driver support"
+       depends on X86_64
+       ---help---
+       Support for the Unisys SPAR drivers
+
+if UNISYSSPAR
+
+source "drivers/staging/unisys/visorutil/Kconfig"
+
+endif # UNISYSSPAR
diff --git a/drivers/staging/unisys/Makefile b/drivers/staging/unisys/Makefile
new file mode 100644 (file)
index 0000000..129c28f
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for Unisys SPAR drivers
+#
+obj-$(CONFIG_UNISYS_VISORUTIL)         += visorutil/
+
diff --git a/drivers/staging/unisys/include/periodic_work.h b/drivers/staging/unisys/include/periodic_work.h
new file mode 100644 (file)
index 0000000..6e725df
--- /dev/null
@@ -0,0 +1,40 @@
+/* periodic_work.h
+ *
+ * Copyright © 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.
+ */
+
+#ifndef __PERIODIC_WORK_H__
+#define __PERIODIC_WORK_H__
+
+#include "timskmod.h"
+
+
+
+/* PERIODIC_WORK an opaque structure to users.
+ * Fields are declared only in the implementation .c files.
+ */
+typedef struct PERIODIC_WORK_Tag PERIODIC_WORK;
+
+PERIODIC_WORK *periodic_work_create(ulong jiffy_interval,
+                                    struct workqueue_struct *workqueue,
+                                    void (*workfunc)(void *),
+                                    void *workfuncarg,
+                                    const char *devnam);
+void            periodic_work_destroy(PERIODIC_WORK *periodic_work);
+BOOL            periodic_work_nextperiod(PERIODIC_WORK *periodic_work);
+BOOL            periodic_work_start(PERIODIC_WORK *periodic_work);
+BOOL            periodic_work_stop(PERIODIC_WORK *periodic_work);
+
+#endif
diff --git a/drivers/staging/unisys/include/procobjecttree.h b/drivers/staging/unisys/include/procobjecttree.h
new file mode 100644 (file)
index 0000000..d3b69f4
--- /dev/null
@@ -0,0 +1,48 @@
+/* procobjecttree.h
+ *
+ * Copyright © 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 creating a tree of types,
+ *  objects, and properties in /proc.
+ *
+ ******************************************************************************
+ */
+
+#ifndef __PROCOBJECTTREE_H__
+#define __PROCOBJECTTREE_H__
+
+#include "uniklog.h"
+#include "timskmod.h"
+
+/* These are opaque structures to users.
+ * Fields are declared only in the implementation .c files.
+ */
+typedef struct MYPROCOBJECT_Tag MYPROCOBJECT;
+typedef struct MYPROCTYPE_Tag   MYPROCTYPE;
+
+MYPROCOBJECT *proc_CreateObject(MYPROCTYPE *type, const char *name,
+                               void *context);
+void          proc_DestroyObject(MYPROCOBJECT *obj);
+MYPROCTYPE   *proc_CreateType(struct proc_dir_entry *procRootDir,
+                             const char **name,
+                             const char **propertyNames,
+                             void (*show_property)(struct seq_file *,
+                                                   void *, int));
+void          proc_DestroyType(MYPROCTYPE *type);
+
+#endif
diff --git a/drivers/staging/unisys/include/timskmod.h b/drivers/staging/unisys/include/timskmod.h
new file mode 100644 (file)
index 0000000..0d0b29c
--- /dev/null
@@ -0,0 +1,558 @@
+/* timskmod.h
+ *
+ * Copyright � 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.
+ */
+
+#ifndef __TIMSKMOD_H__
+#define __TIMSKMOD_H__
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <linux/cdev.h>
+#include <linux/types.h>
+#include <asm/irq.h>
+#include <linux/io.h>
+#include <asm/dma.h>
+#include <linux/uaccess.h>
+#include <linux/list.h>
+#include <linux/poll.h>
+/* #define EXPORT_SYMTAB */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/fcntl.h>
+#include <linux/aio.h>
+#include <linux/workqueue.h>
+#include <linux/kthread.h>
+#include <linux/seq_file.h>
+#include <linux/mm.h>
+
+/* #define DEBUG */
+#ifndef BOOL
+#define BOOL    int
+#endif
+#define FALSE   0
+#define TRUE    1
+#if !defined SUCCESS
+#define SUCCESS 0
+#endif
+#define FAILURE (-1)
+#define DRIVERNAMEMAX 50
+#define MIN(a, b)     (((a) < (b)) ? (a) : (b))
+#define MAX(a, b)     (((a) > (b)) ? (a) : (b))
+#define STRUCTSEQUAL(x, y) (memcmp(&x, &y, sizeof(x)) == 0)
+#ifndef HOSTADDRESS
+#define HOSTADDRESS unsigned long long
+#endif
+
+typedef long VMMIO;  /**< Virtual MMIO address (returned from ioremap), which
+    *   is a virtual address pointer to a memory-mapped region.
+    *   These are declared as "long" instead of u32* to force you to
+    *   use readb()/writeb()/memcpy_fromio()/etc to access them.
+    *   (On x86 we could probably get away with treating them as
+    *   pointers.)
+    */
+typedef long VMMIO8; /**< #VMMIO pointing to  8-bit data */
+typedef long VMMIO16;/**< #VMMIO pointing to 16-bit data */
+typedef long VMMIO32;/**< #VMMIO pointing to 32-bit data */
+
+#define LOCKSEM(sem)                   down_interruptible(sem)
+#define LOCKSEM_UNINTERRUPTIBLE(sem)   down(sem)
+#define UNLOCKSEM(sem)                 up(sem)
+
+/** lock read/write semaphore for reading.
+    Note that all read/write semaphores are of the "uninterruptible" variety.
+    @param sem (rw_semaphore *) points to semaphore to lock
+ */
+#define LOCKREADSEM(sem)               down_read(sem)
+
+/** unlock read/write semaphore for reading.
+    Note that all read/write semaphores are of the "uninterruptible" variety.
+    @param sem (rw_semaphore *) points to semaphore to unlock
+ */
+#define UNLOCKREADSEM(sem)             up_read(sem)
+
+/** lock read/write semaphore for writing.
+    Note that all read/write semaphores are of the "uninterruptible" variety.
+    @param sem (rw_semaphore *) points to semaphore to lock
+ */
+#define LOCKWRITESEM(sem)              down_write(sem)
+
+/** unlock read/write semaphore for writing.
+    Note that all read/write semaphores are of the "uninterruptible" variety.
+    @param sem (rw_semaphore *) points to semaphore to unlock
+ */
+#define UNLOCKWRITESEM(sem)            up_write(sem)
+
+#ifdef ENABLE_RETURN_TRACE
+#define RETTRACE(x)                                            \
+       do {                                                   \
+               if (1) {                                       \
+                       INFODRV("RET 0x%lx in %s",             \
+                               (ulong)(x), __func__);     \
+               }                                          \
+       } while (0)
+#else
+#define RETTRACE(x)
+#endif
+
+/** return from a void function, using a common exit point "Away" */
+#define RETVOID    do { RETTRACE(0); goto Away; } while (0)
+/** return from an int function, using a common exit point "Away"
+ *  @param x the value to return
+ */
+#define RETINT(x)  do { rc = (x); RETTRACE(x); goto Away; } while (0)
+/** return from a void* function, using a common exit point "Away"
+ *  @param x the value to return
+ */
+#define RETPTR(x)  do { rc = (x); RETTRACE(x); goto Away; } while (0)
+/** return from a BOOL function, using a common exit point "Away"
+ *  @param x the value to return
+ */
+#define RETBOOL(x) do { rc = (x); RETTRACE(x); goto Away; } while (0)
+/** Given a typedef/struct/union and a member field name,
+ *  return the number of bytes occupied by that field.
+ *  @param TYPE     the typedef name, or "struct xx" or "union xx"
+ *  @param MEMBER   the name of the member field whose size is to be determined
+ *  @return         the size of the field in bytes
+ */
+#define FAIL(msg, status) do {          \
+               ERRDRV("'%s'"                                         \
+                      ": error (status=%d)\n",                       \
+                      msg, status);                                  \
+               RETINT(status);                                       \
+       } while (0)
+#define FAIL_WPOSTCODE_1(msg, status, EVENT_PC) do {          \
+               ERRDRV("'%s'"                                         \
+                      ": error (status=%d)\n",                       \
+                      msg, status);                                    \
+               POSTCODE_LINUX_2(EVENT_PC, DIAG_SEVERITY_ERR);          \
+               RETINT(status);                                         \
+       } while (0)
+#define FAIL_WPOSTCODE_2(msg, status, EVENT_PC, pcval32bit) do {          \
+               ERRDRV("'%s'"                                           \
+                      ": error (status=%d)\n",                         \
+                      msg, status);                                    \
+               POSTCODE_LINUX_3(EVENT_PC, pcval32bit, DIAG_SEVERITY_ERR); \
+               RETINT(status);                                         \
+       } while (0)
+#define FAIL_WPOSTCODE_3(msg, status, EVENT_PC, pcval16bit1, pcval16bit2) \
+       do {                                                            \
+               ERRDRV("'%s'"                                           \
+                      ": error (status=%d)\n",                         \
+                      msg, status);                                    \
+               POSTCODE_LINUX_4(EVENT_PC, pcval16bit1, pcval16bit2,    \
+                                DIAG_SEVERITY_ERR);                    \
+               RETINT(status);                                         \
+       } while (0)
+/** Try to evaulate the provided expression, and do a RETINT(x) iff
+ *  the expression evaluates to < 0.
+ *  @param x the expression to try
+ */
+#define TRY(x) do { int status = (x);                          \
+               if (status < 0)                                \
+                       FAIL(__stringify(x), status);          \
+       } while (0)
+
+#define TRY_WPOSTCODE_1(x, EVENT_PC) do { \
+               int status = (x);         \
+               if (status < 0)                                         \
+                       FAIL_WPOSTCODE_1(__stringify(x), status, EVENT_PC); \
+       } while (0)
+
+#define TRY_WPOSTCODE_2(x, EVENT_PC, pcval32bit) do { \
+               int status = (x);                     \
+               if (status < 0)                                         \
+                       FAIL_WPOSTCODE_2(__stringify(x), status, EVENT_PC, \
+                                        pcval32bit);                   \
+       } while (0)
+
+#define TRY_WPOSTCODE_3(x, EVENT_PC, pcval16bit1, pcval16bit2) do { \
+               int status = (x);                                   \
+               if (status < 0)                                         \
+                       FAIL_WPOSTCODE_3(__stringify(x), status, EVENT_PC, \
+                                        pcval16bit1, pcval16bit2);     \
+       } while (0)
+
+#define ASSERT(cond)                                           \
+       do { if (!(cond))                                      \
+                       HUHDRV("ASSERT failed - %s",           \
+                              __stringify(cond));             \
+       } while (0)
+
+#define sizeofmember(TYPE, MEMBER) (sizeof(((TYPE *)0)->MEMBER))
+/** "Covered quotient" function */
+#define COVQ(v, d)  (((v) + (d) - 1) / (d))
+#define SWAPPOINTERS(p1, p2)                           \
+       do {                                            \
+               void *SWAPPOINTERS_TEMP = (void *)p1;   \
+               (void *)(p1) = (void *)(p2);            \
+               (void *)(p2) = SWAPPOINTERS_TEMP;       \
+       } while (0)
+
+/**
+ *  @addtogroup driverlogging
+ *  @{
+ */
+
+#define PRINTKDRV(fmt, args...) LOGINF(fmt, ## args)
+#define TBDDRV(fmt, args...)    LOGERR(fmt, ## args)
+#define HUHDRV(fmt, args...)    LOGERR(fmt, ## args)
+#define ERRDRV(fmt, args...)    LOGERR(fmt, ## args)
+#define WARNDRV(fmt, args...)   LOGWRN(fmt, ## args)
+#define SECUREDRV(fmt, args...) LOGWRN(fmt, ## args)
+#define INFODRV(fmt, args...)   LOGINF(fmt, ## args)
+#define DEBUGDRV(fmt, args...)  DBGINF(fmt, ## args)
+
+#define PRINTKDEV(devname, fmt, args...)  LOGINFDEV(devname, fmt, ## args)
+#define TBDDEV(devname, fmt, args...)     LOGERRDEV(devname, fmt, ## args)
+#define HUHDEV(devname, fmt, args...)     LOGERRDEV(devname, fmt, ## args)
+#define ERRDEV(devname, fmt, args...)     LOGERRDEV(devname, fmt, ## args)
+#define ERRDEVX(devno, fmt, args...)     LOGERRDEVX(devno, fmt, ## args)
+#define WARNDEV(devname, fmt, args...)    LOGWRNDEV(devname, fmt, ## args)
+#define SECUREDEV(devname, fmt, args...)  LOGWRNDEV(devname, fmt, ## args)
+#define INFODEV(devname, fmt, args...)    LOGINFDEV(devname, fmt, ## args)
+#define INFODEVX(devno, fmt, args...)     LOGINFDEVX(devno, fmt, ## args)
+#define DEBUGDEV(devname, fmt, args...)   DBGINFDEV(devname, fmt, ## args)
+
+
+/* @} */
+
+/** Used to add a single line to the /proc filesystem buffer */
+#define ADDPROCLINE(buf, bufsize, line, linelen, totallen) \
+       {                                                  \
+               if ((totallen) + (linelen) >= bufsize)     \
+                       RETINT(totallen);                  \
+               if (linelen > 0) {                         \
+                       strcat(buf, line);                 \
+                       totallen += linelen;               \
+               }                                          \
+       }
+
+
+
+/** Verifies the consistency of your PRIVATEDEVICEDATA structure using
+ *  conventional "signature" fields:
+ *  <p>
+ *  - sig1 should contain the size of the structure
+ *  - sig2 should contain a pointer to the beginning of the structure
+ */
+#define DDLOOKSVALID(dd)                                 \
+               ((dd != NULL)                             &&    \
+                ((dd)->sig1 == sizeof(PRIVATEDEVICEDATA)) &&   \
+                ((dd)->sig2 == dd))
+
+/** Verifies the consistency of your PRIVATEFILEDATA structure using
+ *  conventional "signature" fields:
+ *  <p>
+ *  - sig1 should contain the size of the structure
+ *  - sig2 should contain a pointer to the beginning of the structure
+ */
+#define FDLOOKSVALID(fd)                               \
+       ((fd != NULL)                           &&     \
+        ((fd)->sig1 == sizeof(PRIVATEFILEDATA)) &&    \
+        ((fd)->sig2 == fd))
+
+/** Verifies the consistency of a PRIVATEDEVICEDATA structure and reacts
+ *  if necessary
+ */
+#define CHKDDX(dd, x) (                                           \
+                       if (!DDLOOKSVALID((dd))) {         \
+                               PRINTKDRV("bad device structure");      \
+                               RETINT(x);                              \
+                       })
+
+/** Verifies the consistency of a PRIVATEDEVICEDATA structure and reacts
+ *  if necessary
+ */
+#define CHKDD(dd) (                                                    \
+                       if (!DDLOOKSVALID(dd)) {                        \
+                               PRINTKDRV("bad device structure");      \
+                               RETVOID;                                \
+                       })
+
+/** Verifies the consistency of a PRIVATEFILEDATA structure and reacts
+ *  if necessary
+ */
+#define CHKFDX(fd, x) (                                           \
+               if (!FDLOOKSVALID(fd)) {                   \
+                       PRINTKDRV("bad file structure");   \
+                       RETINT(x);                         \
+               })
+
+/** Verifies the consistency of a PRIVATEFILEDATA structure and reacts
+ *  if necessary
+ */
+#define CHKFD(fd) (                                      \
+               if (!FDLOOKSVALID(fd)) {                  \
+                       PRINTKDRV("bad file structure");  \
+                       RETVOID;                          \
+               })
+
+/** Converts a device index #devix into #devData, after checking for validity.
+ *  Can only be called from functions returning void.
+ *  @param devix your device index within the #DevData array.
+ *  @param devData the #PRIVATEDEVICEDATA pointer that will be set on return.
+ *  @param where string identifying the calling function, to be printed in
+ *         debug message
+ *  @param dbg 1 iff debug messages are enabled
+ */
+#define DEVFROMID(devix, devData, where, dbg)                          \
+       {                                                               \
+               if (devix >= MAXDEVICES) {                              \
+                       PRINTKDRV("bad devix passed to %s()", where);   \
+                       RETVOID;                                        \
+               }                                                       \
+               if (dbg)                                                \
+                       DEBUGDEV(devix, "%s", where);                   \
+               if (devix >= MAXDEVICES) {                              \
+                       DEBUGDEV(devix, "%s - bad devix %d",            \
+                                where, devix);                         \
+                       RETVOID;                                        \
+               }                                                       \
+               devData = DevData[devix];                               \
+               CHKDD(devData);                                         \
+       }
+
+/** Converts a device index #devix into #devData, after checking for validity.
+ *  Can only be called from functions returning int.
+ *  @param devix your device index within the #DevData array.
+ *  @param devData the #PRIVATEDEVICEDATA pointer that will be set on return.
+ *  @param errcode error code that your function will return on error.
+ *  @param where string identifying the calling function, to be printed in
+ *         debug message
+ *  @param dbg 1 iff debug messages are enabled
+ */
+#define DEVFROMIDX(devix, devData, errcode, where, dbg)                        \
+       {                                                               \
+               if (devix >= MAXDEVICES) {                              \
+                       PRINTKDRV("bad devix passed to %s()", where);   \
+                       RETINT(errcode);                                \
+               }                                                       \
+               if (dbg)                                                \
+                       DEBUGDEV(devix, "%s", where);                   \
+               if (devix >= MAXDEVICES) {                              \
+                       DEBUGDEV(devix, "%s - bad devix %d",            \
+                                where, devix);                         \
+                       RETINT(-ENODEV);                                \
+               }                                                       \
+               devData = DevData[devix];                               \
+               CHKDDX(devData, -EIO);                                  \
+       }
+
+/** Converts an inode pointer #inode into a #devix and #devData, after
+ *  checking for validity.
+ *  Can only be called from functions returning int.
+ *  @param devix your device index within the #DevData array.
+ *  @param devData the #PRIVATEDEVICEDATA pointer that will be set on return.
+ *  @param inode input inode pointer
+ *  @param errcode error code that your function will return on error.
+ *  @param where string identifying the calling function, to be printed in
+ *         debug message
+ *  @param dbg 1 iff debug messages are enabled
+ */
+#define DEVFROMINODE(devix, devData, inode, errcode, where, dbg)       \
+       {                                                               \
+               if (inode == NULL) {                                    \
+                       PRINTKDRV("bad inode passed to %s()", where);   \
+                       RETINT(errcode);                                \
+               }                                                       \
+               devix = MINOR(inode->i_rdev);                           \
+               if (dbg)                                                \
+                       DEBUGDEV(devix, "%s", where);                   \
+               if (devix >= MAXDEVICES) {                              \
+                       DEBUGDEV(devix, "%s - bad devix %d",            \
+                                where, devix);                         \
+                       RETINT(-ENODEV);                                \
+               }                                                       \
+               devData = DevData[devix];                               \
+               CHKDDX(devData, -EIO);                                  \
+       }
+
+/** Converts a file pointer #file into a #devix and #devData, after checking
+ *  for validity.
+ *  Can only be called from functions returning int.
+ *  @param devix your device index within the #DevData array.
+ *  @param devData the #PRIVATEDEVICEDATA pointer that will be set on return.
+ *  @param file input file pointer
+ *  @param errcode error code that your function will return on error.
+ *  @param where string identifying the calling function, to be printed in
+ *         debug message
+ *  @param dbg 1 iff debug messages are enabled
+ */
+#define DEVFROMFILE(devix, devData, fileData, file, errcode, where, dbg) \
+               {                                                       \
+               if (file == NULL) {                                     \
+                       PRINTKDRV("bad file passed to %s()", where);    \
+                       RETINT(errcode);                                \
+               }                                                       \
+               CHKFDX((PRIVATEFILEDATA *)(file->private_data), -EIO);  \
+               fileData = file->private_data;                          \
+               devix = fileData->devix;                                \
+               if (dbg)                                                \
+                       DEBUGDEV(devix, "%s %p", where, file);          \
+               if (devix >= MAXDEVICES) {                              \
+                       DEBUGDEV(devix, "%s - bad devix %d",            \
+                                where, devix);                         \
+                       RETINT(-ENODEV);                                \
+               }                                                       \
+               devData = DevData[devix];                               \
+               CHKDDX(devData, -EIO);                                  \
+       }
+
+/** Locks dd->lockDev if you havn't already locked it */
+#define LOCKDEV(dd)                                                    \
+       {                                                              \
+               if (!lockedDev) {                                      \
+                       spin_lock(&dd->lockDev);                       \
+                       lockedDev = TRUE;                              \
+               }                                                      \
+       }
+
+/** Unlocks dd->lockDev if you previously locked it */
+#define UNLOCKDEV(dd)                                                  \
+       {                                                              \
+               if (lockedDev) {                                       \
+                       spin_unlock(&dd->lockDev);                     \
+                       lockedDev = FALSE;                             \
+               }                                                      \
+       }
+
+/** Locks dd->lockDevISR if you havn't already locked it */
+#define LOCKDEVISR(dd)                                                 \
+       {                                                              \
+               if (!lockedDevISR) {                                   \
+                       spin_lock_irqsave(&dd->lockDevISR, flags);     \
+                       lockedDevISR = TRUE;                           \
+               }                                                      \
+       }
+
+/** Unlocks dd->lockDevISR if you previously locked it */
+#define UNLOCKDEVISR(dd)                                               \
+       {                                                               \
+               if (lockedDevISR) {                                     \
+                       spin_unlock_irqrestore(&dd->lockDevISR, flags); \
+                       lockedDevISR = FALSE;                           \
+               }                                                       \
+       }
+
+/** Locks LockGlobalISR if you havn't already locked it */
+#define LOCKGLOBALISR                                                  \
+       {                                                              \
+               if (!lockedGlobalISR) {                                \
+                       spin_lock_irqsave(&LockGlobalISR, flags);      \
+                       lockedGlobalISR = TRUE;                        \
+               }                                                      \
+       }
+
+/** Unlocks LockGlobalISR if you previously locked it */
+#define UNLOCKGLOBALISR                                                \
+       {                                                              \
+               if (lockedGlobalISR) {                                 \
+                       spin_unlock_irqrestore(&LockGlobalISR, flags); \
+                       lockedGlobalISR = FALSE;                       \
+               }                                                      \
+       }
+
+/** Locks LockGlobal if you havn't already locked it */
+#define LOCKGLOBAL                                                     \
+       {                                                              \
+               if (!lockedGlobal) {                                   \
+                       spin_lock(&LockGlobal);                        \
+                       lockedGlobal = TRUE;                           \
+               }                                                      \
+       }
+
+/** Unlocks LockGlobal if you previously locked it */
+#define UNLOCKGLOBAL                                                   \
+       {                                                              \
+               if (lockedGlobal) {                                    \
+                       spin_unlock(&LockGlobal);                      \
+                       lockedGlobal = FALSE;                          \
+               }                                                      \
+       }
+
+/** Use this at the beginning of functions where you intend to
+ *  use #LOCKDEV/#UNLOCKDEV, #LOCKDEVISR/#UNLOCKDEVISR,
+ *  #LOCKGLOBAL/#UNLOCKGLOBAL, #LOCKGLOBALISR/#UNLOCKGLOBALISR.
+ *
+ *  Note that __attribute__((unused)) is how you tell GNU C to suppress
+ *  any warning messages about the variable being unused.
+ */
+#define LOCKPREAMBLE                                                   \
+       ulong flags __attribute__((unused)) = 0;                        \
+       BOOL lockedDev __attribute__((unused)) = FALSE;                 \
+       BOOL lockedDevISR __attribute__((unused)) = FALSE;              \
+       BOOL lockedGlobal __attribute__((unused)) = FALSE;              \
+       BOOL lockedGlobalISR __attribute__((unused)) = FALSE
+
+
+
+/** Sleep for an indicated number of seconds (for use in kernel mode).
+ *  @param x the number of seconds to sleep.
+ */
+#define SLEEP(x)                                            \
+       do { current->state = TASK_INTERRUPTIBLE;            \
+               schedule_timeout((x)*HZ);                    \
+       } while (0)
+
+/** Sleep for an indicated number of jiffies (for use in kernel mode).
+ *  @param x the number of jiffies to sleep.
+ */
+#define SLEEPJIFFIES(x)                                                    \
+       do { current->state = TASK_INTERRUPTIBLE;                   \
+               schedule_timeout(x);                                \
+       } while (0)
+
+#ifndef max
+#define max(a, b) (((a) > (b)) ? (a):(b))
+#endif
+
+static inline struct cdev *cdev_alloc_init(struct module *owner,
+                                          const struct file_operations *fops)
+{
+       struct cdev *cdev = NULL;
+       cdev = cdev_alloc();
+       if (!cdev)
+               return NULL;
+       cdev->ops = fops;
+       cdev->owner = owner;
+
+       /* Note that the memory allocated for cdev will be deallocated
+        * when the usage count drops to 0, because it is controlled
+        * by a kobject of type ktype_cdev_dynamic.  (This
+        * deallocation could very well happen outside of our kernel
+        * module, like via the cdev_put in __fput() for example.)
+        */
+       return cdev;
+}
+
+#include "timskmodutils.h"
+
+#endif
diff --git a/drivers/staging/unisys/include/timskmodutils.h b/drivers/staging/unisys/include/timskmodutils.h
new file mode 100644 (file)
index 0000000..ad4175e
--- /dev/null
@@ -0,0 +1,194 @@
+/* timskmodutils.h
+ *
+ * Copyright © 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.
+ */
+
+#ifndef __TIMSKMODUTILS_H__
+#define __TIMSKMODUTILS_H__
+
+#include "timskmod.h"
+
+void *kmalloc_kernel(size_t siz);
+void *kmalloc_kernel_dma(size_t siz);
+void  kfree_kernel(const void *p, size_t siz);
+void *vmalloc_kernel(size_t siz);
+void  vfree_kernel(const void *p, size_t siz);
+void *pgalloc_kernel(size_t siz);
+void  pgfree_kernel(const void *p, size_t siz);
+void  myprintk(const char *myDrvName, const char *devname,
+               const char *template, ...);
+void  myprintkx(const char *myDrvName, int devno, const char *template, ...);
+
+/** Print the hexadecimal contents of a data buffer to a supplied print buffer.
+ *  @param dest               the print buffer where text characters will be
+ *                            written
+ *  @param destSize           the maximum number of bytes that can be written
+ *                            to #dest
+ *  @param src                the buffer that contains the data that is to be
+ *                            hex-dumped
+ *  @param srcLen             the number of bytes at #src to be hex-dumped
+ *  @param bytesToDumpPerLine output will be formatted such that at most this
+ *                            many of the input data bytes will be represented
+ *                            on each line of output
+ *  @return                   the number of text characters written to #dest
+ *                            (not including the trailing '\0' byte)
+ *  @ingroup internal
+ */
+int   hexDumpToBuffer(char *dest,
+                     int destSize,
+                     char *prefix,
+                     char *src,
+                     int srcLen,
+                     int bytesToDumpPerLine);
+
+/** Print the hexadecimal contents of a data buffer to a supplied print buffer.
+ *  Assume the data buffer contains 32-bit words in little-endian format,
+ *  and dump the words with MSB first and LSB last.
+ *  @param dest               the print buffer where text characters will be
+ *                            written
+ *  @param destSize           the maximum number of bytes that can be written
+ *                            to #dest
+ *  @param src                the buffer that contains the data that is to be
+ *                            hex-dumped
+ *  @param srcWords           the number of 32-bit words at #src to be
+ &                            hex-dumped
+ *  @param wordsToDumpPerLine output will be formatted such that at most this
+ *                            many of the input data words will be represented
+ *                            on each line of output
+ *  @return                   the number of text characters written to #dest
+ *                            (not including the trailing '\0' byte)
+ *  @ingroup internal
+ */
+int   hexDumpWordsToBuffer(char *dest,
+                          int destSize,
+                          char *prefix,
+                          uint32_t *src,
+                          int srcWords,
+                          int wordsToDumpPerLine);
+
+
+/** Use printk to print the hexadecimal contents of a data buffer.
+ *  See #INFOHEXDRV and #INFOHEXDEV for info.
+ *  @ingroup internal
+ */
+int myPrintkHexDump(char *myDrvName,
+                   char *devname,
+                   char *prefix,
+                   char *src,
+                   int srcLen,
+                   int bytesToDumpPerLine);
+
+/** Given as input a number of seconds in #seconds, creates text describing
+ *  the time within #s.  Also breaks down the number of seconds into component
+ *  days, hours, minutes, and seconds, and stores to *#days, *#hours,
+ *  *#minutes, and *#secondsx.
+ *  @param seconds input number of seconds
+ *  @param days    points to a long value where the days component for the
+ *                 days+hours+minutes+seconds representation of #seconds will
+ *                 be stored
+ *  @param hours   points to a long value where the hours component for the
+ *                 days+hours+minutes+seconds representation of #seconds will
+ *                 be stored
+ *  @param minutes points to a long value where the minutes component for the
+ *                 days+hours+minutes+seconds representation of #seconds will
+ *                 be stored
+ *  @param secondsx points to a long value where the seconds component for the
+ *                 days+hours+minutes+seconds representation of #seconds will
+ *                 be stored
+ *  @param s       points to a character buffer where a text representation of
+ *                 the #seconds value will be stored.  This buffer MUST be
+ *                 large enough to hold the resulting string; to be safe it
+ *                 should be at least 100 bytes long.
+ */
+void  expandSeconds(time_t seconds,
+                   long *days, long *hours,
+                   long *minutes,
+                   long *secondsx,
+                   char *s);
+
+/*--------------------------------*
+ *---  GENERAL MESSAGEQ STUFF  ---*
+ *--------------------------------*/
+
+struct MessageQEntry;
+
+/** the data structure used to hold an arbitrary data item that you want
+ *  to place on a #MESSAGEQ.  Declare and initialize as follows:
+ *  @code
+ *      MESSAGEQENTRY myEntry;
+ *      initMessageQEntry (&myEntry, pointerToMyDataItem);
+ *  @endcode
+ *  This structure should be considered opaque; the client using it should
+ *  never access the fields directly.
+ *  Refer to these functions for more info:
+ *  - initMessageQ()
+ *  - initMessageQEntry()
+ *  - enqueueMessage()
+ *  - dequeueMessage()
+ *  - dequeueMessageNoBlock()
+ *  - getQueueCount()
+ *
+ *  @ingroup messageq
+ */
+typedef struct MessageQEntry {
+       void *data;
+       struct MessageQEntry *qNext;
+       struct MessageQEntry *qPrev;
+} MESSAGEQENTRY;
+
+/** the data structure used to hold a FIFO queue of #MESSAGEQENTRY<b></b>s.
+ *  Declare and initialize as follows:
+ *  @code
+ *      MESSAGEQ myQueue;
+ *      initMessageQ (&myQueue);
+ *  @endcode
+ *  This structure should be considered opaque; the client using it should
+ *  never access the fields directly.
+ *  Refer to these functions for more info:
+ *  - initMessageQ()
+ *  - initMessageQEntry()
+ *  - enqueueMessage()
+ *  - dequeueMessage()
+ *  - dequeueMessageNoBlock()
+ *  - getQueueCount()
+ *
+ *  @ingroup messageq
+ */
+typedef struct MessageQ {
+       MESSAGEQENTRY *qHead;
+       MESSAGEQENTRY *qTail;
+       struct semaphore nQEntries;
+       spinlock_t       queueLock;
+} MESSAGEQ;
+
+char *cyclesToSeconds(u64 cycles, u64 cyclesPerSecond,
+                     char *buf, size_t bufsize);
+char *cyclesToIterationSeconds(u64 cycles, u64 cyclesPerSecond,
+                              u64 iterations, char *buf, size_t bufsize);
+char *cyclesToSomethingsPerSecond(u64 cycles, u64 cyclesPerSecond,
+                                 u64 somethings, char *buf, size_t bufsize);
+void initMessageQ(MESSAGEQ *q);
+void initMessageQEntry(MESSAGEQENTRY *p, void *data);
+MESSAGEQENTRY *dequeueMessage(MESSAGEQ *q);
+MESSAGEQENTRY *dequeueMessageNoBlock(MESSAGEQ *q);
+void enqueueMessage(MESSAGEQ *q, MESSAGEQENTRY *pEntry);
+size_t getQueueCount(MESSAGEQ *q);
+int waitQueueLen(wait_queue_head_t *q);
+void debugWaitQ(wait_queue_head_t *q);
+struct seq_file *seq_file_new_buffer(void *buf, size_t buf_size);
+void seq_file_done_buffer(struct seq_file *m);
+void seq_hexdump(struct seq_file *seq, u8 *pfx, void *buf, ulong nbytes);
+
+#endif
diff --git a/drivers/staging/unisys/include/uniklog.h b/drivers/staging/unisys/include/uniklog.h
new file mode 100644 (file)
index 0000000..4d7b87c
--- /dev/null
@@ -0,0 +1,193 @@
+/* uniklog.h
+ *
+ * Copyright © 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.
+ */
+
+/* This module contains macros to aid developers in logging messages.
+ *
+ * This module is affected by the DEBUG compiletime option.
+ *
+ */
+#ifndef __UNIKLOG_H__
+#define __UNIKLOG_H__
+
+
+#include <linux/printk.h>
+
+/*
+ * # DBGINF
+ *
+ * \brief Log debug informational message - log a LOG_INFO message only
+ *        if DEBUG compiletime option enabled
+ *
+ * \param devname the device name of the device reporting this message, or
+ *                NULL if this message is NOT device-related.
+ * \param fmt printf()-style format string containing the message to log.
+ * \param args Optional arguments to be formatted and inserted into the
+ *             format string.
+ * \return nothing
+ *
+ * Log a message at the LOG_INFO level, but only if DEBUG is enabled.  If
+ * DEBUG is disabled, this expands to a no-op.
+ */
+
+/*
+ * # DBGVER
+ *
+ * \brief Log debug verbose message - log a LOG_DEBUG message only if
+ *        DEBUG compiletime option enabled
+ *
+ * \param devname the device name of the device reporting this message, or
+ *                NULL if this message is NOT device-related.
+ * \param fmt printf()-style format string containing the message to log.
+ * \param args Optional arguments to be formatted and inserted into the
+ *             format string.
+ * \return nothing
+ *
+ * Log a message at the LOG_DEBUG level, but only if DEBUG is enabled.  If
+ * DEBUG is disabled, this expands to a no-op.  Note also that LOG_DEBUG
+ * messages can be enabled/disabled at runtime as well.
+ */
+#define DBGINFDEV(devname, fmt, args...)        do { } while (0)
+#define DBGVERDEV(devname, fmt, args...)        do { } while (0)
+#define DBGINF(fmt, args...)                    do { } while (0)
+#define DBGVER(fmt, args...)                    do { } while (0)
+
+/*
+ * # LOGINF
+ *
+ * \brief Log informational message - logs a message at the LOG_INFO level
+ *
+ * \param devname the device name of the device reporting this message, or
+ *                NULL if this message is NOT device-related.
+ * \param fmt printf()-style format string containing the message to log.
+ * \param args Optional arguments to be formatted and inserted into the
+ *             format string.
+ * \return nothing
+ *
+ * Logs the specified message at the LOG_INFO level.
+ */
+
+#define LOGINF(fmt, args...) pr_info(fmt, ## args)
+#define LOGINFDEV(devname, fmt, args...) \
+       pr_info("%s " fmt, devname, ## args)
+#define LOGINFDEVX(devno, fmt, args...) \
+       pr_info("dev%d " fmt, devno, ## args)
+#define LOGINFNAME(vnic, fmt, args...)                         \
+       do {                                                            \
+               if (vnic != NULL) {                                     \
+                       pr_info("%s " fmt, vnic->name, ## args);        \
+               } else {                                                \
+                       pr_info(fmt, ## args);                          \
+               }                                                       \
+       } while (0)
+
+/*
+ * # LOGVER
+ *
+ * \brief Log verbose message - logs a message at the LOG_DEBUG level,
+ *        which can be disabled at runtime
+ *
+ * \param devname the device name of the device reporting this message, or
+ *                NULL if this message is NOT device-related.
+ * \param fmt printf()-style format string containing the message to log.
+ * \param args Optional arguments to be formatted and inserted into the format
+ * \param string.
+ * \return nothing
+ *
+ * Logs the specified message at the LOG_DEBUG level.  Note also that
+ * LOG_DEBUG messages can be enabled/disabled at runtime as well.
+ */
+#define LOGVER(fmt, args...) pr_debug(fmt, ## args)
+#define LOGVERDEV(devname, fmt, args...) \
+       pr_debug("%s " fmt, devname, ## args)
+#define LOGVERNAME(vnic, fmt, args...)                                 \
+       do {                                                            \
+               if (vnic != NULL) {                                     \
+                       pr_debug("%s " fmt, vnic->name, ## args);       \
+               } else {                                                \
+                       pr_debug(fmt, ## args);                         \
+               }                                                       \
+       } while (0)
+
+
+/*
+ * # LOGERR
+ *
+ * \brief Log error message - logs a message at the LOG_ERR level,
+ *        including source line number information
+ *
+ * \param devname the device name of the device reporting this message, or
+ *                NULL if this message is NOT device-related.
+ * \param fmt printf()-style format string containing the message to log.
+ * \param args Optional arguments to be formatted and inserted into the format
+ * \param string.
+ * \return nothing
+ *
+ * Logs the specified error message at the LOG_ERR level.  It will also
+ * include the file, line number, and function name of where the error
+ * originated in the log message.
+ */
+#define LOGERR(fmt, args...) pr_err(fmt, ## args)
+#define LOGERRDEV(devname, fmt, args...) \
+       pr_err("%s " fmt, devname, ## args)
+#define LOGERRDEVX(devno, fmt, args...) \
+       pr_err("dev%d " fmt, devno, ## args)
+#define LOGERRNAME(vnic, fmt, args...)                         \
+       do {                                                            \
+               if (vnic != NULL) {                                     \
+                       pr_err("%s " fmt, vnic->name, ## args); \
+               } else {                                                \
+                       pr_err(fmt, ## args);                           \
+               }                                                       \
+       } while (0)
+#define LOGORDUMPERR(seqfile, fmt, args...) do {               \
+               if (seqfile) {                                  \
+                       seq_printf(seqfile, fmt, ## args);      \
+               } else {                                        \
+                       LOGERR(fmt, ## args);                   \
+               }                                               \
+       } while (0)
+
+/*
+ * # LOGWRN
+ *
+ * \brief Log warning message - Logs a message at the LOG_WARNING level,
+ *        including source line number information
+ *
+ * \param devname the device name of the device reporting this message, or
+ *                NULL if this message is NOT device-related.
+ * \param fmt printf()-style format string containing the message to log.
+ * \param args Optional arguments to be formatted and inserted into the format
+ * \param string.
+ * \return nothing
+ *
+ * Logs the specified error message at the LOG_WARNING level.  It will also
+ * include the file, line number, and function name of where the error
+ * originated in the log message.
+ */
+#define LOGWRN(fmt, args...) pr_warn(fmt, ## args)
+#define LOGWRNDEV(devname, fmt, args...) \
+       pr_warn("%s " fmt, devname, ## args)
+#define LOGWRNNAME(vnic, fmt, args...) \
+       do {                                                            \
+               if (vnic != NULL) {                                     \
+                       pr_warn("%s " fmt, vnic->name, ## args);        \
+               } else {                                                \
+                       pr_warn(fmt, ## args);                          \
+               }                                                       \
+       } while (0)
+
+#endif /* __UNIKLOG_H__ */
diff --git a/drivers/staging/unisys/visorutil/Kconfig b/drivers/staging/unisys/visorutil/Kconfig
new file mode 100644 (file)
index 0000000..4ff61a7
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Unisys timskmod configuration
+#
+
+config UNISYS_VISORUTIL
+       tristate "Unisys visorutil driver"
+       depends on UNISYSSPAR
+       ---help---
+       If you say Y here, you will enable the Unisys visorutil driver.
+
diff --git a/drivers/staging/unisys/visorutil/Makefile b/drivers/staging/unisys/visorutil/Makefile
new file mode 100644 (file)
index 0000000..3f46388
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Makefile for Unisys timskmod
+#
+
+obj-$(CONFIG_UNISYS_VISORUTIL) += visorutil.o
+
+visorutil-y := charqueue.o  easyproc.o  periodic_work.o  procobjecttree.o  \
+               memregion_direct.o visorkmodutils.o
+
+ccflags-y += -Idrivers/staging/unisys/include
+ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION
diff --git a/drivers/staging/unisys/visorutil/charqueue.c b/drivers/staging/unisys/visorutil/charqueue.c
new file mode 100644 (file)
index 0000000..2bce94e
--- /dev/null
@@ -0,0 +1,144 @@
+/* charqueue.c
+ *
+ * Copyright © 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.
+ */
+
+/*
+ *  Simple character queue implementation for Linux kernel mode.
+ */
+
+#include "charqueue.h"
+
+#define MYDRVNAME "charqueue"
+
+#define IS_EMPTY(charqueue) (charqueue->head == charqueue->tail)
+
+
+
+struct CHARQUEUE_Tag {
+       int alloc_size;
+       int nslots;
+       spinlock_t lock;
+       int head, tail;
+       unsigned char buf[0];
+};
+
+
+
+CHARQUEUE *charqueue_create(ulong nslots)
+{
+       int alloc_size = sizeof(CHARQUEUE) + nslots + 1;
+       CHARQUEUE *cq = kmalloc(alloc_size, GFP_KERNEL|__GFP_NORETRY);
+       if (cq == NULL) {
+               ERRDRV("charqueue_create allocation failed (alloc_size=%d)",
+                      alloc_size);
+               return NULL;
+       }
+       cq->alloc_size = alloc_size;
+       cq->nslots = nslots;
+       cq->head = cq->tail = 0;
+       spin_lock_init(&cq->lock);
+       return cq;
+}
+EXPORT_SYMBOL_GPL(charqueue_create);
+
+
+
+void charqueue_enqueue(CHARQUEUE *charqueue, unsigned char c)
+{
+       int alloc_slots = charqueue->nslots+1;  /* 1 slot is always empty */
+
+       spin_lock(&charqueue->lock);
+       charqueue->head = (charqueue->head+1) % alloc_slots;
+       if (charqueue->head == charqueue->tail)
+               /* overflow; overwrite the oldest entry */
+               charqueue->tail = (charqueue->tail+1) % alloc_slots;
+       charqueue->buf[charqueue->head] = c;
+       spin_unlock(&charqueue->lock);
+}
+EXPORT_SYMBOL_GPL(charqueue_enqueue);
+
+
+
+BOOL charqueue_is_empty(CHARQUEUE *charqueue)
+{
+       BOOL b;
+       spin_lock(&charqueue->lock);
+       b = IS_EMPTY(charqueue);
+       spin_unlock(&charqueue->lock);
+       return b;
+}
+EXPORT_SYMBOL_GPL(charqueue_is_empty);
+
+
+
+static int charqueue_dequeue_1(CHARQUEUE *charqueue)
+{
+       int alloc_slots = charqueue->nslots + 1;  /* 1 slot is always empty */
+
+       if (IS_EMPTY(charqueue))
+               return -1;
+       charqueue->tail = (charqueue->tail+1) % alloc_slots;
+       return charqueue->buf[charqueue->tail];
+}
+
+
+
+int charqueue_dequeue(CHARQUEUE *charqueue)
+{
+       int rc = -1;
+
+       spin_lock(&charqueue->lock);
+       RETINT(charqueue_dequeue_1(charqueue));
+Away:
+       spin_unlock(&charqueue->lock);
+       return rc;
+}
+
+
+
+int charqueue_dequeue_n(CHARQUEUE *charqueue, unsigned char *buf, int n)
+{
+       int rc = -1, counter = 0, c;
+
+       spin_lock(&charqueue->lock);
+       for (;;) {
+               if (n <= 0)
+                       break;  /* no more buffer space */
+               c = charqueue_dequeue_1(charqueue);
+               if (c < 0)
+                       break;  /* no more input */
+               *buf = (unsigned char)(c);
+               buf++;
+               n--;
+               counter++;
+       }
+       RETINT(counter);
+
+Away:
+       spin_unlock(&charqueue->lock);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(charqueue_dequeue_n);
+
+
+
+void charqueue_destroy(CHARQUEUE *charqueue)
+{
+       if (charqueue == NULL)
+               return;
+       kfree(charqueue);
+}
+EXPORT_SYMBOL_GPL(charqueue_destroy);
diff --git a/drivers/staging/unisys/visorutil/charqueue.h b/drivers/staging/unisys/visorutil/charqueue.h
new file mode 100644 (file)
index 0000000..e9ce0a9
--- /dev/null
@@ -0,0 +1,37 @@
+/* charqueue.h
+ *
+ * Copyright © 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.
+ */
+
+#ifndef __CHARQUEUE_H__
+#define __CHARQUEUE_H__
+
+#include "uniklog.h"
+#include "timskmod.h"
+
+/* CHARQUEUE is an opaque structure to users.
+ * Fields are declared only in the implementation .c files.
+ */
+typedef struct CHARQUEUE_Tag CHARQUEUE;
+
+CHARQUEUE *charqueue_create(ulong nslots);
+void charqueue_enqueue(CHARQUEUE *charqueue, unsigned char c);
+int charqueue_dequeue(CHARQUEUE *charqueue);
+int charqueue_dequeue_n(CHARQUEUE *charqueue, unsigned char *buf, int n);
+BOOL charqueue_is_empty(CHARQUEUE *charqueue);
+void charqueue_destroy(CHARQUEUE *charqueue);
+
+#endif
+
diff --git a/drivers/staging/unisys/visorutil/easyproc.c b/drivers/staging/unisys/visorutil/easyproc.c
new file mode 100644 (file)
index 0000000..2b750ee
--- /dev/null
@@ -0,0 +1,365 @@
+/* Copyright © 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
+ *  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 easyproc_InitDevice().
+ *
+ ******************************************************************************
+ */
+
+#include <linux/proc_fs.h>
+
+#include "uniklog.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);
+       if (p == NULL)
+               ERRDRV("failed to create /proc directory %s", name);
+       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 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;
+       if (pdriver->ProcId == NULL)
+               ERRDRV("ProcId cannot be NULL (trouble ahead)!");
+       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);
+               if (pdriver->ProcDriverDiagFile == NULL)
+                       ERRDRV("failed to register /proc/%s/driver/diag entry",
+                              pdriver->ProcId);
+       }
+}
+EXPORT_SYMBOL_GPL(easyproc_InitDriver);
+
+
+
+void 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))
+{
+       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(easyproc_InitDriverEx);
+
+
+
+void 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(easyproc_DeInitDriver);
+
+
+
+void 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);
+               if (p->procDevicexDiagFile == NULL)
+                       ERRDEVX(devno, "failed to register /proc/%s/device/%d/diag entry",
+                               pdriver->ProcId, devno
+                              );
+       }
+       memset(&(p->device_property_info[0]), 0,
+              sizeof(p->device_property_info));
+}
+EXPORT_SYMBOL_GPL(easyproc_InitDevice);
+
+
+
+void 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) {
+               ERRDRV("state error");
+               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) {
+               ERRDEVX(p->devno, "too many device properties");
+               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)) {
+               ERRDEVX(p->devno, "device property name %s too long",
+                       property_name);
+               return;
+       }
+       strcpy(px->property_name, property_name);
+       if (px->procEntry == NULL) {
+               ERRDEVX(p->devno, "failed to register /proc/%s/device/%d/%s entry",
+                       p->pdriver->ProcId, p->devno, property_name
+                      );
+               return;
+       }
+       px->show_device_property_info = show_property_info;
+}
+EXPORT_SYMBOL_GPL(easyproc_CreateDeviceProperty);
+
+
+
+void 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(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;
+}
diff --git a/drivers/staging/unisys/visorutil/easyproc.h b/drivers/staging/unisys/visorutil/easyproc.h
new file mode 100644 (file)
index 0000000..a1b4df7
--- /dev/null
@@ -0,0 +1,86 @@
+/* easyproc.h
+ *
+ * Copyright © 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 easyproc_InitDevice(struct easyproc_driver_info *pdriver,
+                        struct easyproc_device_info *p, int devno,
+                        void *devdata);
+void easyproc_DeInitDevice(struct easyproc_driver_info *pdriver,
+                          struct easyproc_device_info *p, int devno);
+void 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 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 easyproc_DeInitDriver(struct easyproc_driver_info *pdriver);
+void easyproc_CreateDeviceProperty(struct easyproc_device_info *p,
+                                  void (*show_property_info)(struct seq_file *, void *),
+                                  char *property_name);
+
+#endif
diff --git a/drivers/staging/unisys/visorutil/memregion.h b/drivers/staging/unisys/visorutil/memregion.h
new file mode 100644 (file)
index 0000000..a1fce7b
--- /dev/null
@@ -0,0 +1,43 @@
+/* memregion.h
+ *
+ * Copyright © 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.
+ */
+
+#ifndef __MEMREGION_H__
+#define __MEMREGION_H__
+
+#include "timskmod.h"
+
+/* MEMREGION is an opaque structure to users.
+ * Fields are declared only in the implementation .c files.
+ */
+typedef struct MEMREGION_Tag MEMREGION;
+
+MEMREGION *memregion_create(HOSTADDRESS physaddr, ulong nbytes);
+MEMREGION *memregion_create_overlapped(MEMREGION *parent,
+                                      ulong offset, ulong nbytes);
+int memregion_resize(MEMREGION *memregion, ulong newsize);
+int memregion_read(MEMREGION *memregion,
+                  ulong offset, void *dest, ulong nbytes);
+int memregion_write(MEMREGION *memregion,
+                   ulong offset, void *src, ulong nbytes);
+void memregion_destroy(MEMREGION *memregion);
+HOSTADDRESS memregion_get_physaddr(MEMREGION *memregion);
+ulong memregion_get_nbytes(MEMREGION *memregion);
+void memregion_dump(MEMREGION *memregion, char *s,
+                   ulong off, ulong len, struct seq_file *seq);
+void *memregion_get_pointer(MEMREGION *memregion);
+
+#endif
diff --git a/drivers/staging/unisys/visorutil/memregion_direct.c b/drivers/staging/unisys/visorutil/memregion_direct.c
new file mode 100644 (file)
index 0000000..fbb460f
--- /dev/null
@@ -0,0 +1,221 @@
+/* memregion_direct.c
+ *
+ * Copyright © 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.
+ */
+
+/*
+ *  This is an implementation of memory regions that can be used to read/write
+ *  channel memory (in main memory of the host system) from code running in
+ *  a virtual partition.
+ */
+#include "uniklog.h"
+#include "timskmod.h"
+#include "memregion.h"
+
+#define MYDRVNAME "memregion"
+
+struct MEMREGION_Tag {
+       HOSTADDRESS physaddr;
+       ulong nbytes;
+       void *mapped;
+       BOOL requested;
+       BOOL overlapped;
+};
+
+static BOOL mapit(MEMREGION *memregion);
+static void unmapit(MEMREGION *memregion);
+
+MEMREGION *
+memregion_create(HOSTADDRESS physaddr, ulong nbytes)
+{
+       MEMREGION *rc = NULL;
+       MEMREGION *memregion = kmalloc(sizeof(MEMREGION),
+                                      GFP_KERNEL|__GFP_NORETRY);
+       if (memregion == NULL) {
+               ERRDRV("memregion_create allocation failed");
+               return NULL;
+       }
+       memset(memregion, 0, sizeof(MEMREGION));
+       memregion->physaddr = physaddr;
+       memregion->nbytes = nbytes;
+       memregion->overlapped = FALSE;
+       if (!mapit(memregion))
+               RETPTR(NULL);
+       RETPTR(memregion);
+
+Away:
+       if (rc == NULL) {
+               if (memregion != NULL) {
+                       memregion_destroy(memregion);
+                       memregion = NULL;
+               }
+       }
+       return rc;
+}
+EXPORT_SYMBOL_GPL(memregion_create);
+
+MEMREGION *
+memregion_create_overlapped(MEMREGION *parent, ulong offset, ulong nbytes)
+{
+       MEMREGION *memregion = NULL;
+
+       if (parent == NULL) {
+               ERRDRV("%s parent is NULL", __func__);
+               return NULL;
+       }
+       if (parent->mapped == NULL) {
+               ERRDRV("%s parent is not mapped!", __func__);
+               return NULL;
+       }
+       if ((offset >= parent->nbytes) ||
+           ((offset + nbytes) >= parent->nbytes)) {
+               ERRDRV("%s range (%lu,%lu) out of parent range",
+                      __func__, offset, nbytes);
+               return NULL;
+       }
+       memregion = kmalloc(sizeof(MEMREGION), GFP_KERNEL|__GFP_NORETRY);
+       if (memregion == NULL) {
+               ERRDRV("%s allocation failed", __func__);
+               return NULL;
+       }
+       memset(memregion, 0, sizeof(MEMREGION));
+       memregion->physaddr = parent->physaddr + offset;
+       memregion->nbytes = nbytes;
+       memregion->mapped = ((u8 *) (parent->mapped)) + offset;
+       memregion->requested = FALSE;
+       memregion->overlapped = TRUE;
+       return memregion;
+}
+EXPORT_SYMBOL_GPL(memregion_create_overlapped);
+
+
+static BOOL
+mapit(MEMREGION *memregion)
+{
+       ulong physaddr = (ulong) (memregion->physaddr);
+       ulong nbytes = memregion->nbytes;
+
+       memregion->requested = FALSE;
+       if (!request_mem_region(physaddr, nbytes, MYDRVNAME))
+               ERRDRV("cannot reserve channel memory @0x%lx for 0x%lx-- no big deal", physaddr, nbytes);
+       else
+               memregion->requested = TRUE;
+       memregion->mapped = ioremap_cache(physaddr, nbytes);
+       if (memregion->mapped == NULL) {
+               ERRDRV("cannot ioremap_cache channel memory @0x%lx for 0x%lx",
+                      physaddr, nbytes);
+               return FALSE;
+       }
+       return TRUE;
+}
+
+static void
+unmapit(MEMREGION *memregion)
+{
+       if (memregion->mapped != NULL) {
+               iounmap(memregion->mapped);
+               memregion->mapped = NULL;
+       }
+       if (memregion->requested) {
+               release_mem_region((ulong) (memregion->physaddr),
+                                  memregion->nbytes);
+               memregion->requested = FALSE;
+       }
+}
+
+HOSTADDRESS
+memregion_get_physaddr(MEMREGION *memregion)
+{
+       return memregion->physaddr;
+}
+EXPORT_SYMBOL_GPL(memregion_get_physaddr);
+
+ulong
+memregion_get_nbytes(MEMREGION *memregion)
+{
+       return memregion->nbytes;
+}
+EXPORT_SYMBOL_GPL(memregion_get_nbytes);
+
+void *
+memregion_get_pointer(MEMREGION *memregion)
+{
+       return memregion->mapped;
+}
+EXPORT_SYMBOL_GPL(memregion_get_pointer);
+
+int
+memregion_resize(MEMREGION *memregion, ulong newsize)
+{
+       if (newsize == memregion->nbytes)
+               return 0;
+       if (memregion->overlapped)
+               /* no error check here - we no longer know the
+                * parent's range!
+                */
+               memregion->nbytes = newsize;
+       else {
+               unmapit(memregion);
+               memregion->nbytes = newsize;
+               if (!mapit(memregion))
+                       return -1;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(memregion_resize);
+
+
+static int
+memregion_readwrite(BOOL is_write,
+                   MEMREGION *memregion, ulong offset,
+                   void *local, ulong nbytes)
+{
+       if (offset + nbytes > memregion->nbytes) {
+               ERRDRV("memregion_readwrite offset out of range!!");
+               return -EFAULT;
+       }
+       if (is_write)
+               memcpy_toio(memregion->mapped + offset, local, nbytes);
+       else
+               memcpy_fromio(local, memregion->mapped + offset, nbytes);
+
+       return 0;
+}
+
+int
+memregion_read(MEMREGION *memregion, ulong offset, void *dest, ulong nbytes)
+{
+       return memregion_readwrite(FALSE, memregion, offset, dest, nbytes);
+}
+EXPORT_SYMBOL_GPL(memregion_read);
+
+int
+memregion_write(MEMREGION *memregion, ulong offset, void *src, ulong nbytes)
+{
+       return memregion_readwrite(TRUE, memregion, offset, src, nbytes);
+}
+EXPORT_SYMBOL_GPL(memregion_write);
+
+void
+memregion_destroy(MEMREGION *memregion)
+{
+       if (memregion == NULL)
+               return;
+       if (!memregion->overlapped)
+               unmapit(memregion);
+       kfree(memregion);
+}
+EXPORT_SYMBOL_GPL(memregion_destroy);
+
diff --git a/drivers/staging/unisys/visorutil/periodic_work.c b/drivers/staging/unisys/visorutil/periodic_work.c
new file mode 100644 (file)
index 0000000..1350b8e
--- /dev/null
@@ -0,0 +1,230 @@
+/* periodic_work.c
+ *
+ * Copyright © 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.
+ */
+
+/*
+ *  Helper functions to schedule periodic work in Linux kernel mode.
+ */
+
+#include "uniklog.h"
+#include "timskmod.h"
+#include "periodic_work.h"
+
+#define MYDRVNAME "periodic_work"
+
+
+
+struct PERIODIC_WORK_Tag {
+       rwlock_t lock;
+       struct delayed_work work;
+       void (*workfunc)(void *);
+       void *workfuncarg;
+       BOOL is_scheduled;
+       BOOL want_to_stop;
+       ulong jiffy_interval;
+       struct workqueue_struct *workqueue;
+       const char *devnam;
+};
+
+
+
+static void periodic_work_func(struct work_struct *work)
+{
+       PERIODIC_WORK *periodic_work =
+               container_of(work, struct PERIODIC_WORK_Tag, work.work);
+       (*periodic_work->workfunc)(periodic_work->workfuncarg);
+}
+
+
+
+PERIODIC_WORK *periodic_work_create(ulong jiffy_interval,
+                                     struct workqueue_struct *workqueue,
+                                     void (*workfunc)(void *),
+                                     void *workfuncarg,
+                                     const char *devnam)
+{
+       PERIODIC_WORK *periodic_work = kmalloc(sizeof(PERIODIC_WORK),
+                                              GFP_KERNEL|__GFP_NORETRY);
+       if (periodic_work == NULL) {
+               ERRDRV("periodic_work allocation failed ");
+               return NULL;
+       }
+       memset(periodic_work, '\0', sizeof(PERIODIC_WORK));
+       rwlock_init(&periodic_work->lock);
+       periodic_work->jiffy_interval = jiffy_interval;
+       periodic_work->workqueue = workqueue;
+       periodic_work->workfunc = workfunc;
+       periodic_work->workfuncarg = workfuncarg;
+       periodic_work->devnam = devnam;
+       return periodic_work;
+}
+EXPORT_SYMBOL_GPL(periodic_work_create);
+
+
+
+void periodic_work_destroy(PERIODIC_WORK *periodic_work)
+{
+       if (periodic_work == NULL)
+               return;
+       kfree(periodic_work);
+}
+EXPORT_SYMBOL_GPL(periodic_work_destroy);
+
+
+
+/** Call this from your periodic work worker function to schedule the next
+ *  call.
+ *  If this function returns FALSE, there was a failure and the
+ *  periodic work is no longer scheduled
+ */
+BOOL periodic_work_nextperiod(PERIODIC_WORK *periodic_work)
+{
+       BOOL rc = FALSE;
+       write_lock(&periodic_work->lock);
+       if (periodic_work->want_to_stop) {
+               periodic_work->is_scheduled = FALSE;
+               periodic_work->want_to_stop = FALSE;
+               RETBOOL(TRUE);  /* yes, TRUE; see periodic_work_stop() */
+       } else if (queue_delayed_work(periodic_work->workqueue,
+                                     &periodic_work->work,
+                                     periodic_work->jiffy_interval) < 0) {
+               ERRDEV(periodic_work->devnam, "queue_delayed_work failed!");
+               periodic_work->is_scheduled = FALSE;
+               RETBOOL(FALSE);
+       }
+       RETBOOL(TRUE);
+Away:
+       write_unlock(&periodic_work->lock);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(periodic_work_nextperiod);
+
+
+
+/** This function returns TRUE iff new periodic work was actually started.
+ *  If this function returns FALSE, then no work was started
+ *  (either because it was already started, or because of a failure).
+ */
+BOOL periodic_work_start(PERIODIC_WORK *periodic_work)
+{
+       BOOL rc = FALSE;
+
+       write_lock(&periodic_work->lock);
+       if (periodic_work->is_scheduled)
+               RETBOOL(FALSE);
+       if (periodic_work->want_to_stop) {
+               ERRDEV(periodic_work->devnam,
+                      "dev_start_periodic_work failed!");
+               RETBOOL(FALSE);
+       }
+       INIT_DELAYED_WORK(&periodic_work->work, &periodic_work_func);
+       if (queue_delayed_work(periodic_work->workqueue,
+                              &periodic_work->work,
+                              periodic_work->jiffy_interval) < 0) {
+               ERRDEV(periodic_work->devnam,
+                      "%s queue_delayed_work failed!", __func__);
+               RETBOOL(FALSE);
+       }
+       periodic_work->is_scheduled = TRUE;
+       RETBOOL(TRUE);
+Away:
+       write_unlock(&periodic_work->lock);
+       return rc;
+
+}
+EXPORT_SYMBOL_GPL(periodic_work_start);
+
+
+
+
+/** This function returns TRUE iff your call actually stopped the periodic
+ *  work.
+ *
+ *  -- PAY ATTENTION... this is important --
+ *
+ *  NO NO #1
+ *
+ *     Do NOT call this function from some function that is running on the
+ *     same workqueue as the work you are trying to stop might be running
+ *     on!  If you violate this rule, periodic_work_stop() MIGHT work, but it
+ *     also MIGHT get hung up in an infinite loop saying
+ *     "waiting for delayed work...".  This will happen if the delayed work
+ *     you are trying to cancel has been put in the workqueue list, but can't
+ *     run yet because we are running that same workqueue thread right now.
+ *
+ *     Bottom line: If you need to call periodic_work_stop() from a workitem,
+ *     be sure the workitem is on a DIFFERENT workqueue than the workitem that
+ *     you are trying to cancel.
+ *
+ *     If I could figure out some way to check for this "no no" condition in
+ *     the code, I would.  It would have saved me the trouble of writing this
+ *     long comment.  And also, don't think this is some "theoretical" race
+ *     condition.  It is REAL, as I have spent the day chasing it.
+ *
+ *  NO NO #2
+ *
+ *     Take close note of the locks that you own when you call this function.
+ *     You must NOT own any locks that are needed by the periodic work
+ *     function that is currently installed.  If you DO, a deadlock may result,
+ *     because stopping the periodic work often involves waiting for the last
+ *     iteration of the periodic work function to complete.  Again, if you hit
+ *     this deadlock, you will get hung up in an infinite loop saying
+ *     "waiting for delayed work...".
+ */
+BOOL periodic_work_stop(PERIODIC_WORK *periodic_work)
+{
+       BOOL stopped_something = FALSE;
+
+       write_lock(&periodic_work->lock);
+       stopped_something = periodic_work->is_scheduled &&
+               (!periodic_work->want_to_stop);
+       while (periodic_work->is_scheduled) {
+               periodic_work->want_to_stop = TRUE;
+               if (cancel_delayed_work(&periodic_work->work)) {
+                       /* We get here if the delayed work was pending as
+                        * delayed work, but was NOT run.
+                        */
+                       ASSERT(periodic_work->is_scheduled);
+                       periodic_work->is_scheduled = FALSE;
+               } else {
+                       /* If we get here, either the delayed work:
+                        * - was run, OR,
+                        * - is running RIGHT NOW on another processor, OR,
+                        * - wasn't even scheduled (there is a miniscule
+                        *   timing window where this could be the case)
+                        * flush_workqueue() would make sure it is finished
+                        * executing, but that still isn't very useful, which
+                        * explains the loop...
+                        */
+               }
+               if (periodic_work->is_scheduled) {
+                       write_unlock(&periodic_work->lock);
+                       WARNDEV(periodic_work->devnam,
+                               "waiting for delayed work...");
+                       /* We rely on the delayed work function running here,
+                        * and eventually calling periodic_work_nextperiod(),
+                        * which will see that want_to_stop is set, and
+                        * subsequently clear is_scheduled.
+                        */
+                       SLEEPJIFFIES(10);
+                       write_lock(&periodic_work->lock);
+               } else
+                       periodic_work->want_to_stop = FALSE;
+       }
+       write_unlock(&periodic_work->lock);
+       return stopped_something;
+}
+EXPORT_SYMBOL_GPL(periodic_work_stop);
diff --git a/drivers/staging/unisys/visorutil/procobjecttree.c b/drivers/staging/unisys/visorutil/procobjecttree.c
new file mode 100644 (file)
index 0000000..f59b37e
--- /dev/null
@@ -0,0 +1,334 @@
+/* procobjecttree.c
+ *
+ * Copyright © 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.
+ */
+typedef struct {
+       void (*show_property)(struct seq_file *, void *, int);
+       MYPROCOBJECT *procObject;
+       int propertyIndex;
+
+} PROCDIRENTRYCONTEXT;
+
+/** 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 */
+       PROCDIRENTRYCONTEXT *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);
+       if (p == NULL)
+               ERRDRV("failed to create /proc directory %s", name);
+       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);
+       if (p == NULL)
+               ERRDRV("failed to create /proc file %s", name);
+       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 *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)
+               FAIL("procDirRoot cannot be NULL!", 0);
+       if (name == NULL || name[0] == NULL)
+               FAIL("name must contain at least 1 node name!", 0);
+       type = kmalloc(sizeof(MYPROCTYPE), GFP_KERNEL|__GFP_NORETRY);
+       if (type == NULL)
+               FAIL("out of memory", 0);
+       memset(type, 0, sizeof(MYPROCTYPE));
+       type->name = name;
+       type->propertyNames = propertyNames;
+       type->nProperties = 0;
+       type->nNames = 0;
+       type->show_property = show_property;
+       type->procDirRoot = procDirRoot;
+       if (type->propertyNames != 0)
+               while (type->propertyNames[type->nProperties] != NULL)
+                       type->nProperties++;
+       while (type->name[type->nNames] != NULL)
+               type->nNames++;
+       type->procDirs = kmalloc((type->nNames+1)*
+                                sizeof(struct proc_dir_entry *),
+                                GFP_KERNEL|__GFP_NORETRY);
+       if (type->procDirs == NULL)
+               FAIL("out of memory", 0);
+       memset(type->procDirs, 0, (type->nNames + 1) *
+              sizeof(struct proc_dir_entry *));
+       parent = procDirRoot;
+       for (i = 0; i < type->nNames; i++) {
+               type->procDirs[i] = createProcDir(type->name[i], parent);
+               if (type->procDirs[i] == NULL)
+                       RETPTR(NULL);
+               parent = type->procDirs[i];
+       }
+       type->procDir = type->procDirs[type->nNames-1];
+       RETPTR(type);
+Away:
+       if (rc == NULL) {
+               if (type != NULL) {
+                       proc_DestroyType(type);
+                       type = NULL;
+               }
+       }
+       return rc;
+}
+EXPORT_SYMBOL_GPL(proc_CreateType);
+
+
+
+void 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(proc_DestroyType);
+
+
+
+MYPROCOBJECT *proc_CreateObject(MYPROCTYPE *type,
+                               const char *name, void *context)
+{
+       MYPROCOBJECT *obj = NULL, *rc = NULL;
+       int i = 0;
+
+       if (type == NULL)
+               FAIL("type cannot be NULL", 0);
+       obj = kmalloc(sizeof(MYPROCOBJECT), GFP_KERNEL | __GFP_NORETRY);
+       if (obj == NULL)
+               FAIL("out of memory", 0);
+       memset(obj, 0, sizeof(MYPROCOBJECT));
+       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;
+                       FAIL("out of memory", 0);
+               }
+               strcpy(obj->name, name);
+               obj->procDir = createProcDir(obj->name, type->procDir);
+               if (obj->procDir == NULL)
+                       RETPTR(NULL);
+       }
+       obj->procDirPropertyContexts =
+               kmalloc((type->nProperties+1)*sizeof(PROCDIRENTRYCONTEXT),
+                       GFP_KERNEL|__GFP_NORETRY);
+       if (obj->procDirPropertyContexts == NULL)
+               FAIL("out of memory", 0);
+       memset(obj->procDirPropertyContexts, 0,
+              (type->nProperties+1)*sizeof(PROCDIRENTRYCONTEXT));
+       obj->procDirProperties =
+               kmalloc((type->nProperties+1) * sizeof(struct proc_dir_entry *),
+                       GFP_KERNEL|__GFP_NORETRY);
+       if (obj->procDirProperties == NULL)
+               FAIL("out of memory", 0);
+       memset(obj->procDirProperties, 0,
+              (type->nProperties+1) * sizeof(struct proc_dir_entry *));
+       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)
+                               RETPTR(NULL);
+               }
+       }
+       RETPTR(obj);
+Away:
+       if (rc == NULL) {
+               if (obj != NULL) {
+                       proc_DestroyObject(obj);
+                       obj = NULL;
+               }
+       }
+       return rc;
+}
+EXPORT_SYMBOL_GPL(proc_CreateObject);
+
+
+
+void 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;
+       }
+       if (obj->procDirPropertyContexts != 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;
+       }
+       if (obj->name != NULL) {
+               kfree(obj->name);
+               obj->name = NULL;
+       }
+       kfree(obj);
+}
+EXPORT_SYMBOL_GPL(proc_DestroyObject);
+
+
+
+static int seq_show(struct seq_file *seq, void *offset)
+{
+       PROCDIRENTRYCONTEXT *ctx = (PROCDIRENTRYCONTEXT *)(seq->private);
+       if (ctx == NULL) {
+               ERRDRV("I don't have a freakin' clue...");
+               return 0;
+       }
+       (*ctx->show_property)(seq, ctx->procObject->context,
+                             ctx->propertyIndex);
+       return 0;
+}
diff --git a/drivers/staging/unisys/visorutil/visorkmodutils.c b/drivers/staging/unisys/visorutil/visorkmodutils.c
new file mode 100644 (file)
index 0000000..13e7326
--- /dev/null
@@ -0,0 +1,721 @@
+/* timskmodutils.c
+ *
+ * Copyright © 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 "uniklog.h"
+#include "timskmod.h"
+
+#define MYDRVNAME "timskmodutils"
+
+BOOL Debug_Malloc_Enabled = FALSE;
+
+
+
+void myprintk(const char *myDrvName, const char *devname,
+              const char *template, ...)
+{
+       va_list ap;
+       char temp[999];
+       char *ptemp = temp;
+       char pfx[20];
+       char msg[sizeof(pfx) + strlen(myDrvName) + 50];
+
+       if (myDrvName == NULL)
+               return;
+       temp[sizeof(temp)-1] = '\0';
+       pfx[0]               = '\0';
+       msg[0]               = '\0';
+       va_start(ap, template);
+       vsprintf(temp, template, ap);
+       va_end(ap);
+       if (temp[0] == '<') {
+               size_t i = 0;
+               for (i = 0; i < sizeof(pfx) - 1; i++) {
+                       pfx[i] = temp[i];
+                       if (pfx[i] == '>' || pfx[i] == '\0') {
+                               if (pfx[i] == '>')
+                                       ptemp = temp+i+1;
+                               i++;
+                               break;
+                       }
+               }
+               pfx[i] = '\0';
+       }
+       if (devname == NULL)
+               sprintf(msg, "%s%s: ", pfx, myDrvName);
+       else
+               sprintf(msg, "%s%s[%s]: ", pfx, myDrvName, devname);
+       printk(KERN_INFO "%s", msg);
+
+       /* The <prefix> applies up until the \n, so we should not include
+        * it in these printks.  That's why we use <ptemp> to point to the
+        * first char after the ">" in the prefix.
+        */
+       printk(KERN_INFO "%s", ptemp);
+       printk("\n");
+
+}
+
+
+
+void myprintkx(const char *myDrvName, int devno, const char *template, ...)
+{
+       va_list ap;
+       char temp[999];
+       char *ptemp = temp;
+       char pfx[20];
+       char msg[sizeof(pfx) + strlen(myDrvName) + 50];
+
+       if (myDrvName == NULL)
+               return;
+       temp[sizeof(temp)-1] = '\0';
+       pfx[0]               = '\0';
+       msg[0]               = '\0';
+       va_start(ap, template);
+       vsprintf(temp, template, ap);
+       va_end(ap);
+       if (temp[0] == '<') {
+               size_t i = 0;
+               for (i = 0; i < sizeof(pfx) - 1; i++) {
+                       pfx[i] = temp[i];
+                       if (pfx[i] == '>' || pfx[i] == '\0') {
+                               if (pfx[i] == '>')
+                                       ptemp = temp+i+1;
+                               i++;
+                               break;
+                       }
+               }
+               pfx[i] = '\0';
+       }
+       if (devno < 0)
+               sprintf(msg, "%s%s: ", pfx, myDrvName);
+       else
+               sprintf(msg, "%s%s[%d]: ", pfx, myDrvName, devno);
+       printk(KERN_INFO "%s", msg);
+
+       /* The <prefix> applies up until the \n, so we should not include
+        * it in these printks.  That's why we use <ptemp> to point to the
+        * first char after the ">" in the prefix.
+        */
+       printk(KERN_INFO "%s", ptemp);
+       printk("\n");
+}
+
+
+
+int hexDumpWordsToBuffer(char *dest,
+                        int destSize,
+                        char *prefix,
+                        uint32_t *src,
+                        int srcWords,
+                        int wordsToDumpPerLine)
+{
+       int i = 0;
+       int pos = 0;
+       char hex[(wordsToDumpPerLine * 9) + 1];
+       char *line = NULL;
+       int linesize = 1000;
+       int linelen = 0;
+       int currentlen = 0;
+       char emptystring[] = "";
+       char *pfx = prefix;
+       int baseaddr = 0;
+       int rc = 0;
+       uint8_t b1, b2, b3, b4;
+
+       line = vmalloc(linesize);
+       if (line == NULL)
+               RETINT(currentlen);
+
+       if (pfx == NULL || (strlen(pfx) > 50))
+               pfx = emptystring;
+       memset(hex, ' ', wordsToDumpPerLine * 9);
+       hex[wordsToDumpPerLine * 9] = '\0';
+       if (destSize > 0)
+               dest[0] = '\0';
+
+       for (i = 0; i < srcWords; i++) {
+               pos = i % wordsToDumpPerLine;
+               if ((pos == 0) && (i > 0)) {
+                       hex[wordsToDumpPerLine * 9] = '\0';
+                       linelen = sprintf(line, "%s%-6.6x %s\n", pfx,
+                                         baseaddr, hex);
+                       if ((currentlen) + (linelen) >= destSize)
+                               RETINT(currentlen);
+                       strcat(dest, line);
+                       currentlen += linelen;
+                       memset(hex, ' ', wordsToDumpPerLine * 9);
+                       baseaddr = i * 4;
+               }
+               b1 = (uint8_t)((src[i] >> 24) & 0xff);
+               b2 = (uint8_t)((src[i] >> 16) & 0xff);
+               b3 = (uint8_t)((src[i] >>  8) & 0xff);
+               b4 = (uint8_t)((src[i]) & 0xff);
+               sprintf(hex + (pos * 9), "%-2.2x%-2.2x%-2.2x%-2.2x ",
+                       b1, b2, b3, b4);
+               *(hex + (pos * 9) + 9) = ' ';  /* get rid of null */
+       }
+       pos = i%wordsToDumpPerLine;
+       if (i > 0) {
+               hex[wordsToDumpPerLine * 9] = '\0';
+               linelen = sprintf(line, "%s%-6.6x %s\n", pfx, baseaddr, hex);
+               if ((currentlen) + (linelen) >= destSize)
+                       RETINT(currentlen);
+               strcat(dest, line);
+               currentlen += linelen;
+       }
+       RETINT(currentlen);
+
+Away:
+       if (line)
+               vfree(line);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(hexDumpWordsToBuffer);
+
+
+
+int myPrintkHexDump(char *myDrvName,
+                   char *devname,
+                   char *prefix,
+                   char *src,
+                   int srcLen,
+                   int bytesToDumpPerLine)
+{
+       int i = 0;
+       int pos = 0;
+       char printable[bytesToDumpPerLine + 1];
+       char hex[(bytesToDumpPerLine*3) + 1];
+       char *line = NULL;
+       int linesize = 1000;
+       int linelen = 0;
+       int currentlen = 0;
+       char emptystring[] = "";
+       char *pfx = prefix;
+       int baseaddr = 0;
+       int rc = 0;
+       int linecount = 0;
+
+       line = vmalloc(linesize);
+       if (line == NULL)
+               RETINT(currentlen);
+
+       if (pfx == NULL || (strlen(pfx) > 50))
+               pfx = emptystring;
+       memset(hex, ' ', bytesToDumpPerLine * 3);
+       hex[bytesToDumpPerLine * 3] = '\0';
+       memset(printable, ' ', bytesToDumpPerLine);
+       printable[bytesToDumpPerLine] = '\0';
+
+       for (i = 0; i < srcLen; i++) {
+               pos = i % bytesToDumpPerLine;
+               if ((pos == 0) && (i > 0)) {
+                       hex[bytesToDumpPerLine*3] = '\0';
+                       linelen = sprintf(line, "%s%-6.6x %s %s",
+                                         pfx, baseaddr, hex, printable);
+                       myprintk(myDrvName, devname, KERN_INFO "%s", line);
+                       currentlen += linelen;
+                       linecount++;
+                       if ((linecount % 50) == 0)
+                               SLEEPJIFFIES(10);
+                       memset(hex, ' ', bytesToDumpPerLine*3);
+                       memset(printable, ' ', bytesToDumpPerLine);
+                       baseaddr = i;
+               }
+               sprintf(hex + (pos * 3), "%-2.2x ", (uint8_t)(src[i]));
+               *(hex + (pos * 3) + 3) = ' ';  /* get rid of null */
+               if (((uint8_t)(src[i]) >= ' ') && (uint8_t)(src[i]) < 127)
+                       printable[pos] = src[i];
+               else
+                       printable[pos] = '.';
+       }
+       pos = i%bytesToDumpPerLine;
+       if (i > 0) {
+               hex[bytesToDumpPerLine*3] = '\0';
+               linelen = sprintf(line, "%s%-6.6x %s %s",
+                                 pfx, baseaddr, hex, printable);
+               myprintk(myDrvName, devname, KERN_INFO "%s", line);
+               currentlen += linelen;
+       }
+       RETINT(currentlen);
+
+Away:
+       if (line)
+               vfree(line);
+       return rc;
+}
+
+
+
+/** Given as input a number of seconds in #seconds, creates text describing
+    the time within #s.  Also breaks down the number of seconds into component
+    days, hours, minutes, and seconds, and stores to *#days, *#hours,
+    *#minutes, and *#secondsx.
+ *  @param seconds input number of seconds
+ *  @param days    points to a long value where the days component for the
+ *                 days+hours+minutes+seconds representation of #seconds will
+ *                 be stored
+ *  @param hours   points to a long value where the hours component for the
+ *                 days+hours+minutes+seconds representation of #seconds will
+ *                 be stored
+ *  @param minutes points to a long value where the minutes component for the
+ *                 days+hours+minutes+seconds representation of #seconds will
+ *                 be stored
+ *  @param secondsx points to a long value where the seconds component for the
+ *                 days+hours+minutes+seconds representation of #seconds will
+ *                 be stored
+ *  @param s       points to a character buffer where a text representation of
+ *                the #seconds value will be stored.  This buffer MUST be
+ *                large enough to hold the resulting string; to be safe it
+ *                should be at least 100 bytes long.
+ */
+void expandSeconds(time_t seconds, long *days, long *hours, long *minutes,
+                  long *secondsx, char *s)
+{
+       BOOL started = FALSE;
+       char buf[99];
+
+       *days = seconds / (60*60*24);
+       seconds -= ((*days)*(60*60*24));
+       *hours = seconds / (60*60);
+       seconds -= ((*hours)*(60*60));
+       *minutes = seconds/60;
+       seconds -= ((*minutes)*60);
+       *secondsx = (long)seconds;
+       if (s == NULL)
+               RETVOID;
+       s[0] = '\0';
+       if (*days > 0) {
+               sprintf(buf, "%lu day", *days);
+               strcat(s, buf);
+               if (*days != 1)
+                       strcat(s, "s");
+               started = TRUE;
+       }
+       if ((*hours > 0) || started) {
+               if (started)
+                       strcat(s, ", ");
+               sprintf(buf, "%lu hour", *hours);
+               strcat(s, buf);
+               if (*hours != 1)
+                       strcat(s, "s");
+               started = TRUE;
+       }
+       if ((*minutes > 0) || started) {
+               if (started)
+                       strcat(s, ", ");
+               sprintf(buf, "%lu minute", *minutes);
+               strcat(s, buf);
+               if (*minutes != 1)
+                       strcat(s, "s");
+               started = TRUE;
+       }
+       if (started)
+               strcat(s, ", ");
+       sprintf(buf, "%lu second", *secondsx);
+       strcat(s, buf);
+       if (*secondsx != 1)
+               strcat(s, "s");
+
+Away:
+       return;
+}
+
+
+
+/** Initialize a #MESSAGEQ for use (initially it will be empty, of course).
+ *  @param q               the #MESSAGEQ to initialize
+ *  @ingroup messageq
+ */
+void initMessageQ(MESSAGEQ *q)
+{
+       q->qHead = NULL;
+       q->qTail = NULL;
+       sema_init(&q->nQEntries, 0);   /* will block initially */
+       spin_lock_init(&q->queueLock);
+}
+
+
+
+/** Initialize #p with your data structure in #data,
+ *  so you can later place #p onto a #MESSAGEQ.
+ *  @param p               the queue entry that will house your data structure
+ *  @param data            a pointer to your data structure that you want
+ *                         to queue
+ *  @ingroup messageq
+ */
+void initMessageQEntry(MESSAGEQENTRY *p, void *data)
+{
+       p->data = data;
+       p->qNext = NULL;
+       p->qPrev = NULL;
+}
+
+
+
+MESSAGEQENTRY *dequeueMessageGuts(MESSAGEQ *q, BOOL canBlock)
+{
+       MESSAGEQENTRY *pEntry = NULL;
+       MESSAGEQENTRY *rc = NULL;
+       BOOL locked = FALSE;
+       ulong flags = 0;
+       int res = 0;
+
+       if (canBlock) {
+               /* wait for non-empty q */
+               res = down_interruptible(&q->nQEntries);
+               if (signal_pending(current)) {
+                       DEBUGDRV("got signal in dequeueMessage");
+                       RETPTR(NULL);
+               }
+       } else if (down_trylock(&q->nQEntries))
+               RETPTR(NULL);
+       spin_lock_irqsave(&q->queueLock, flags);
+       locked = TRUE;
+#ifdef PARANOID
+       if (q->qHead == NULL) {
+               HUHDRV("unexpected empty queue in getQueue");
+               RETPTR(NULL);
+       }
+#endif
+       pEntry = q->qHead;
+       if (pEntry == q->qTail) {
+               /* only 1 item in the queue */
+               q->qHead = NULL;
+               q->qTail = NULL;
+       } else {
+               q->qHead = pEntry->qNext;
+               q->qHead->qPrev = NULL;
+       }
+       RETPTR(pEntry);
+Away:
+       if (locked) {
+               spin_unlock_irqrestore(&q->queueLock, flags);
+               locked = FALSE;
+       }
+       return rc;
+}
+
+
+
+/** Remove the next message at the head of the FIFO queue, and return it.
+ *  Wait for the queue to become non-empty if it is empty when this
+ *  function is called.
+ *  @param q               the queue where the message is to be obtained from
+ *  @return                the queue entry obtained from the head of the
+ *                         FIFO queue, or NULL iff a signal was received
+ *                         while waiting for the queue to become non-empty
+ *  @ingroup messageq
+ */
+MESSAGEQENTRY *dequeueMessage(MESSAGEQ *q)
+{
+       return dequeueMessageGuts(q, TRUE);
+}
+
+
+
+/** Remove the next message at the head of the FIFO queue, and return it.
+ *  This function will never block (it returns NULL instead).
+ *  @param q               the queue where the message is to be obtained from
+ *  @return                the queue entry obtained from the head of the
+ *                         FIFO queue, or NULL iff the queue is empty.
+ *  @ingroup messageq
+ */
+MESSAGEQENTRY *dequeueMessageNoBlock(MESSAGEQ *q)
+{
+       return dequeueMessageGuts(q, FALSE);
+}
+
+
+
+/** Add an entry to a FIFO queue.
+ *  @param q               the queue where the entry is to be added
+ *  @param pEntry          the entry you want to add to the queue
+ *  @ingroup messageq
+ */
+void enqueueMessage(MESSAGEQ *q, MESSAGEQENTRY *pEntry)
+{
+       BOOL locked = FALSE;
+       ulong flags = 0;
+
+       spin_lock_irqsave(&q->queueLock, flags);
+       locked = TRUE;
+       if (q->qHead == NULL) {
+#ifdef PARANOID
+               if (q->qTail != NULL) {
+                       HUHDRV("qHead/qTail not consistent");
+                       RETVOID;
+               }
+#endif
+               q->qHead = pEntry;
+               q->qTail = pEntry;
+               pEntry->qNext = NULL;
+               pEntry->qPrev = NULL;
+       } else {
+#ifdef PARANOID
+               if (q->qTail == NULL) {
+                       HUHDRV("qTail should not be NULL here");
+                       RETVOID;
+               }
+#endif
+               q->qTail->qNext = pEntry;
+               pEntry->qPrev = q->qTail;
+               pEntry->qNext = NULL;
+               q->qTail = pEntry;
+       }
+       spin_unlock_irqrestore(&q->queueLock, flags);
+       locked = FALSE;
+       up(&q->nQEntries);
+       RETVOID;
+Away:
+       if (locked) {
+               spin_unlock_irqrestore(&q->queueLock, flags);
+               locked = FALSE;
+       }
+       return;
+}
+
+
+
+/** Return the number of entries in the queue.
+ *  @param q               the queue to be examined
+ *  @return                the number of entries on #q
+ *  @ingroup messageq
+ */
+size_t getQueueCount(MESSAGEQ *q)
+{
+       return (size_t)__sync_fetch_and_add(&(q->nQEntries.count), 0);
+}
+
+
+
+/** Return the number of processes waiting in a standard wait queue.
+ *  @param q               the pointer to the wait queue to be
+ *                         examined
+ *  @return                the number of waiters
+ *  @ingroup internal
+ */
+int waitQueueLen(wait_queue_head_t *q)
+{
+       struct list_head *x;
+       int count = 0;
+       list_for_each(x, &(q->task_list))
+               count++;
+       return count;
+}
+
+
+
+/** Display information about the processes on a standard wait queue.
+ *  @param q               the pointer to the wait queue to be
+ *                         examined
+ *  @ingroup internal
+ */
+void debugWaitQ(wait_queue_head_t *q)
+{
+       DEBUGDRV("task_list.next= %-8.8x",
+                ((struct __wait_queue_head *)(q))->task_list.next);
+       DEBUGDRV("task_list.prev= %-8.8x",
+                ((struct __wait_queue_head *)(q))->task_list.prev);
+}
+
+
+
+/** Print the hexadecimal contents of a data buffer to a supplied print buffer.
+ *  @param dest               the print buffer where text characters will
+ *                           be written
+ *  @param destSize           the maximum number of bytes that can be written
+ *                           to #dest
+ *  @param src                the buffer that contains the data that is to be
+ *                           hex-dumped
+ *  @param srcLen             the number of bytes at #src to be hex-dumped
+ *  @param bytesToDumpPerLine output will be formatted such that at most
+ *                           this many of the input data bytes will be
+ *                           represented on each line of output
+ *  @return                   the number of text characters written to #dest
+ *                            (not including the trailing '\0' byte)
+ *  @ingroup internal
+ */
+int hexDumpToBuffer(char *dest, int destSize, char *prefix, char *src,
+                   int srcLen, int bytesToDumpPerLine)
+{
+       int i = 0;
+       int pos = 0;
+       char printable[bytesToDumpPerLine + 1];
+       char hex[(bytesToDumpPerLine * 3) + 1];
+       char *line = NULL;
+       int linesize = 1000;
+       int linelen = 0;
+       int currentlen = 0;
+       char emptystring[] = "";
+       char *pfx = prefix;
+       int baseaddr = 0;
+       int rc = 0;
+
+       line = vmalloc(linesize);
+       if (line == NULL)
+               RETINT(currentlen);
+
+       if (pfx == NULL || (strlen(pfx) > 50))
+               pfx = emptystring;
+       memset(hex, ' ', bytesToDumpPerLine * 3);
+       hex[bytesToDumpPerLine * 3] = '\0';
+       memset(printable, ' ', bytesToDumpPerLine);
+       printable[bytesToDumpPerLine] = '\0';
+       if (destSize > 0)
+               dest[0] = '\0';
+
+       for (i = 0; i < srcLen; i++) {
+               pos = i % bytesToDumpPerLine;
+               if ((pos == 0) && (i > 0)) {
+                       hex[bytesToDumpPerLine*3] = '\0';
+                       linelen = sprintf(line, "%s%-6.6x %s %s\n", pfx,
+                                         baseaddr, hex, printable);
+                       if ((currentlen) + (linelen) >= destSize)
+                               RETINT(currentlen);
+                       strcat(dest, line);
+                       currentlen += linelen;
+                       memset(hex, ' ', bytesToDumpPerLine * 3);
+                       memset(printable, ' ', bytesToDumpPerLine);
+                       baseaddr = i;
+               }
+               sprintf(hex + (pos * 3), "%-2.2x ", (uint8_t)(src[i]));
+               *(hex + (pos * 3) + 3) = ' ';  /* get rid of null */
+               if (((uint8_t)(src[i]) >= ' ') && (uint8_t)(src[i]) < 127)
+                       printable[pos] = src[i];
+               else
+                       printable[pos] = '.';
+       }
+       pos = i%bytesToDumpPerLine;
+       if (i > 0) {
+               hex[bytesToDumpPerLine * 3] = '\0';
+               linelen = sprintf(line, "%s%-6.6x %s %s\n",
+                                 pfx, baseaddr, hex, printable);
+               if ((currentlen) + (linelen) >= destSize)
+                       RETINT(currentlen);
+               strcat(dest, line);
+               currentlen += linelen;
+       }
+       RETINT(currentlen);
+
+Away:
+       if (line)
+               vfree(line);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(hexDumpToBuffer);
+
+
+/** Callers to interfaces that set __GFP_NORETRY flag below
+ *  must check for a NULL (error) result as we are telling the
+ *  kernel interface that it is okay to fail.
+ */
+
+void *kmalloc_kernel(size_t siz)
+{
+       return kmalloc(siz, GFP_KERNEL | __GFP_NORETRY);
+}
+
+void *kmalloc_kernel_dma(size_t siz)
+{
+       return kmalloc(siz, GFP_KERNEL | __GFP_NORETRY|GFP_DMA);
+}
+
+void kfree_kernel(const void *p, size_t siz)
+{
+       kfree(p);
+}
+
+void *vmalloc_kernel(size_t siz)
+{
+       return vmalloc((unsigned long)(siz));
+}
+
+void vfree_kernel(const void *p, size_t siz)
+{
+       vfree((void *)(p));
+}
+
+void *pgalloc_kernel(size_t siz)
+{
+       return (void *)__get_free_pages(GFP_KERNEL|__GFP_NORETRY,
+                                      get_order(siz));
+}
+
+void pgfree_kernel(const void *p, size_t siz)
+{
+       free_pages((ulong)(p), get_order(siz));
+}
+
+
+
+/*  Use these handy-dandy seq_file_xxx functions if you want to call some
+ *  functions that write stuff into a seq_file, but you actually just want
+ *  to dump that output into a buffer.  Use them as follows:
+ *  - call seq_file_new_buffer to create the seq_file (you supply the buf)
+ *  - call whatever functions you want that take a seq_file as an argument
+ *    (the buf you supplied will get the output data)
+ *  - call seq_file_done_buffer to dispose of your seq_file
+ */
+struct seq_file *seq_file_new_buffer(void *buf, size_t buf_size)
+{
+       struct seq_file *rc = NULL;
+       struct seq_file *m = kmalloc_kernel(sizeof(struct seq_file));
+
+       if (m == NULL)
+               RETPTR(NULL);
+       memset(m, 0, sizeof(struct seq_file));
+       m->buf = buf;
+       m->size = buf_size;
+       RETPTR(m);
+Away:
+       if (rc == NULL) {
+               seq_file_done_buffer(m);
+               m = NULL;
+       }
+       return rc;
+}
+EXPORT_SYMBOL_GPL(seq_file_new_buffer);
+
+
+
+void seq_file_done_buffer(struct seq_file *m)
+{
+       if (!m)
+               return;
+       kfree(m);
+}
+EXPORT_SYMBOL_GPL(seq_file_done_buffer);
+
+
+
+void seq_hexdump(struct seq_file *seq, u8 *pfx, void *buf, ulong nbytes)
+{
+       int fmtbufsize = 100 * COVQ(nbytes, 16);
+       char *fmtbuf = NULL;
+       int i = 0;
+       if (buf == NULL) {
+               seq_printf(seq, "%s<NULL>\n", pfx);
+               return;
+       }
+       fmtbuf = kmalloc_kernel(fmtbufsize);
+       if (fmtbuf == NULL)
+               return;
+       hexDumpToBuffer(fmtbuf, fmtbufsize, pfx, (char *)(buf), nbytes, 16);
+       for (i = 0; fmtbuf[i] != '\0'; i++)
+               seq_printf(seq, "%c", fmtbuf[i]);
+       kfree(fmtbuf);
+}