[patch 1/8] staging: visorutil driver to provide common functionality to other s-Par drivers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




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@xxxxxxxxxx>
Cc: Ben Romer <sparmaintainer@xxxxxxxxxx>

Index: upstream-staging/drivers/staging/Kconfig
===================================================================
--- upstream-staging.orig/drivers/staging/Kconfig
+++ upstream-staging/drivers/staging/Kconfig
@@ -146,4 +146,6 @@ source "drivers/staging/dgnc/Kconfig"

 source "drivers/staging/dgap/Kconfig"

+source "drivers/staging/unisys/Kconfig"
+
 endif # STAGING
Index: upstream-staging/drivers/staging/Makefile
===================================================================
--- upstream-staging.orig/drivers/staging/Makefile
+++ upstream-staging/drivers/staging/Makefile
@@ -65,3 +65,4 @@ obj-$(CONFIG_XILLYBUS)        += xillybus/
 obj-$(CONFIG_DGNC)            += dgnc/
 obj-$(CONFIG_DGAP)            += dgap/
 obj-$(CONFIG_MTD_SPINAND_MT29F)    += mt29f_spinand/
+obj-$(CONFIG_UNISYSSPAR)    += unisys/
Index: upstream-staging/drivers/staging/unisys/include/periodic_work.h
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/include/periodic_work.h
@@ -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
Index: upstream-staging/drivers/staging/unisys/include/procobjecttree.h
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/include/procobjecttree.h
@@ -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
Index: upstream-staging/drivers/staging/unisys/include/timskmod.h
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/include/timskmod.h
@@ -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
Index: upstream-staging/drivers/staging/unisys/include/timskmodutils.h
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/include/timskmodutils.h
@@ -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
Index: upstream-staging/drivers/staging/unisys/include/uniklog.h
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/include/uniklog.h
@@ -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__ */
Index: upstream-staging/drivers/staging/unisys/visorutil/Kconfig
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorutil/Kconfig
@@ -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.
+
Index: upstream-staging/drivers/staging/unisys/visorutil/Makefile
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorutil/Makefile
@@ -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
Index: upstream-staging/drivers/staging/unisys/visorutil/charqueue.c
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorutil/charqueue.c
@@ -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(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(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(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(charqueue_dequeue_n);
+
+
+
+void charqueue_destroy(CHARQUEUE *charqueue)
+{
+    if (charqueue == NULL)
+        return;
+    kfree(charqueue);
+}
+EXPORT_SYMBOL(charqueue_destroy);
Index: upstream-staging/drivers/staging/unisys/visorutil/charqueue.h
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorutil/charqueue.h
@@ -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
+
Index: upstream-staging/drivers/staging/unisys/visorutil/easyproc.c
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorutil/easyproc.c
@@ -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(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(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(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(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(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(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;
+}
Index: upstream-staging/drivers/staging/unisys/visorutil/easyproc.h
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorutil/easyproc.h
@@ -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
Index: upstream-staging/drivers/staging/unisys/visorutil/memregion.h
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorutil/memregion.h
@@ -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
Index: upstream-staging/drivers/staging/unisys/visorutil/memregion_direct.c
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorutil/memregion_direct.c
@@ -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(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(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(memregion_get_physaddr);
+
+ulong
+memregion_get_nbytes(MEMREGION *memregion)
+{
+    return memregion->nbytes;
+}
+EXPORT_SYMBOL(memregion_get_nbytes);
+
+void *
+memregion_get_pointer(MEMREGION *memregion)
+{
+    return memregion->mapped;
+}
+EXPORT_SYMBOL(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(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(memregion_read);
+
+int
+memregion_write(MEMREGION *memregion, ulong offset, void *src, ulong nbytes)
+{
+    return memregion_readwrite(TRUE, memregion, offset, src, nbytes);
+}
+EXPORT_SYMBOL(memregion_write);
+
+void
+memregion_destroy(MEMREGION *memregion)
+{
+    if (memregion == NULL)
+        return;
+    if (!memregion->overlapped)
+        unmapit(memregion);
+    kfree(memregion);
+}
+EXPORT_SYMBOL(memregion_destroy);
+
Index: upstream-staging/drivers/staging/unisys/visorutil/periodic_work.c
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorutil/periodic_work.c
@@ -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(periodic_work_create);
+
+
+
+void periodic_work_destroy(PERIODIC_WORK *periodic_work)
+{
+    if (periodic_work == NULL)
+        return;
+    kfree(periodic_work);
+}
+EXPORT_SYMBOL(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(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(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(periodic_work_stop);
Index: upstream-staging/drivers/staging/unisys/visorutil/procobjecttree.c
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorutil/procobjecttree.c
@@ -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(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(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(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(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;
+}
Index: upstream-staging/drivers/staging/unisys/visorutil/visorkmodutils.c
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorutil/visorkmodutils.c
@@ -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(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(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(seq_file_new_buffer);
+
+
+
+void seq_file_done_buffer(struct seq_file *m)
+{
+    if (!m)
+        return;
+    kfree(m);
+}
+EXPORT_SYMBOL(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);
+}
Index: upstream-staging/drivers/staging/unisys/Kconfig
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/Kconfig
@@ -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
Index: upstream-staging/drivers/staging/unisys/Makefile
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for Unisys SPAR drivers
+#
+obj-$(CONFIG_UNISYS_VISORUTIL)        += visorutil/
+


_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel





[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux