#include <linux/init.h>
 #include <linux/kbd_kern.h>
 #include <linux/kernel.h>
-#include <linux/kref.h>
 #include <linux/kthread.h>
 #include <linux/list.h>
 #include <linux/module.h>
 static int sysrq_pressed;
 #endif
 
-struct hvc_struct {
-       spinlock_t lock;
-       int index;
-       struct tty_struct *tty;
-       unsigned int count;
-       int do_wakeup;
-       char *outbuf;
-       int outbuf_size;
-       int n_outbuf;
-       uint32_t vtermno;
-       struct hv_ops *ops;
-       int irq_requested;
-       int irq;
-       struct list_head next;
-       struct kref kref; /* ref count & hvc_struct lifetime */
-};
-
 /* dynamic list of hvc_struct instances */
 static LIST_HEAD(hvc_structs);
 
 }
 
 /* Wake the sleeping khvcd */
-static void hvc_kick(void)
+void hvc_kick(void)
 {
        hvc_kicked = 1;
        wake_up_process(hvc_task);
 }
 
-static int hvc_poll(struct hvc_struct *hp);
-
-/*
- * NOTE: This API isn't used if the console adapter doesn't support interrupts.
- * In this case the console is poll driven.
- */
-static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance)
-{
-       /* if hvc_poll request a repoll, then kick the hvcd thread */
-       if (hvc_poll(dev_instance))
-               hvc_kick();
-       return IRQ_HANDLED;
-}
-
 static void hvc_unthrottle(struct tty_struct *tty)
 {
        hvc_kick();
 {
        struct hvc_struct *hp;
        unsigned long flags;
-       int irq = 0;
        int rc = 0;
 
        /* Auto increments kref reference if found. */
        tty->low_latency = 1; /* Makes flushes to ldisc synchronous. */
 
        hp->tty = tty;
-       /* Save for request_irq outside of spin_lock. */
-       irq = hp->irq;
-       if (irq)
-               hp->irq_requested = 1;
+
+       if (hp->ops->notifier_add)
+               rc = hp->ops->notifier_add(hp, hp->data);
 
        spin_unlock_irqrestore(&hp->lock, flags);
-       /* check error, fallback to non-irq */
-       if (irq)
-               rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, "hvc_console", hp);
+
 
        /*
-        * If the request_irq() fails and we return an error.  The tty layer
+        * If the notifier fails we return an error.  The tty layer
         * will call hvc_close() after a failed open but we don't want to clean
         * up there so we'll clean up here and clear out the previously set
         * tty fields and return the kref reference.
        if (rc) {
                spin_lock_irqsave(&hp->lock, flags);
                hp->tty = NULL;
-               hp->irq_requested = 0;
                spin_unlock_irqrestore(&hp->lock, flags);
                tty->driver_data = NULL;
                kref_put(&hp->kref, destroy_hvc_struct);
 static void hvc_close(struct tty_struct *tty, struct file * filp)
 {
        struct hvc_struct *hp;
-       int irq = 0;
        unsigned long flags;
 
        if (tty_hung_up_p(filp))
        spin_lock_irqsave(&hp->lock, flags);
 
        if (--hp->count == 0) {
-               if (hp->irq_requested)
-                       irq = hp->irq;
-               hp->irq_requested = 0;
+               if (hp->ops->notifier_del)
+                       hp->ops->notifier_del(hp, hp->data);
 
                /* We are done with the tty pointer now. */
                hp->tty = NULL;
                 * waking periodically to check chars_in_buffer().
                 */
                tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
-
-               if (irq)
-                       free_irq(irq, hp);
-
        } else {
                if (hp->count < 0)
                        printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
 {
        struct hvc_struct *hp = tty->driver_data;
        unsigned long flags;
-       int irq = 0;
        int temp_open_count;
 
        if (!hp)
        hp->count = 0;
        hp->n_outbuf = 0;
        hp->tty = NULL;
-       if (hp->irq_requested)
-               /* Saved for use outside of spin_lock. */
-               irq = hp->irq;
-       hp->irq_requested = 0;
+
+       if (hp->ops->notifier_del)
+                       hp->ops->notifier_del(hp, hp->data);
+
        spin_unlock_irqrestore(&hp->lock, flags);
-       if (irq)
-               free_irq(irq, hp);
+
        while(temp_open_count) {
                --temp_open_count;
                kref_put(&hp->kref, destroy_hvc_struct);
 #define HVC_POLL_READ  0x00000001
 #define HVC_POLL_WRITE 0x00000002
 
-static int hvc_poll(struct hvc_struct *hp)
+int hvc_poll(struct hvc_struct *hp)
 {
        struct tty_struct *tty;
        int i, n, poll_mask = 0;
        if (test_bit(TTY_THROTTLED, &tty->flags))
                goto throttled;
 
-       /* If we aren't interrupt driven and aren't throttled, we always
+       /* If we aren't notifier driven and aren't throttled, we always
         * request a reschedule
         */
-       if (hp->irq == 0)
+       if (!hp->irq_requested)
                poll_mask |= HVC_POLL_READ;
 
        /* Read data if any */
        .chars_in_buffer = hvc_chars_in_buffer,
 };
 
-struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
+struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data,
                                        struct hv_ops *ops, int outbuf_size)
 {
        struct hvc_struct *hp;
        memset(hp, 0x00, sizeof(*hp));
 
        hp->vtermno = vtermno;
-       hp->irq = irq;
+       hp->data = data;
        hp->ops = ops;
        hp->outbuf_size = outbuf_size;
        hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
 
 
 #ifndef HVC_CONSOLE_H
 #define HVC_CONSOLE_H
+#include <linux/kref.h>
 
 /*
  * This is the max number of console adapters that can/will be found as
  */
 #define HVC_ALLOC_TTY_ADAPTERS 8
 
+struct hvc_struct {
+       spinlock_t lock;
+       int index;
+       struct tty_struct *tty;
+       unsigned int count;
+       int do_wakeup;
+       char *outbuf;
+       int outbuf_size;
+       int n_outbuf;
+       uint32_t vtermno;
+       struct hv_ops *ops;
+       int irq_requested;
+       int data;
+       struct list_head next;
+       struct kref kref; /* ref count & hvc_struct lifetime */
+};
 
 /* implemented by a low level driver */
 struct hv_ops {
        int (*get_chars)(uint32_t vtermno, char *buf, int count);
        int (*put_chars)(uint32_t vtermno, const char *buf, int count);
-};
 
-struct hvc_struct;
+       /* Callbacks for notification. Called in open and close */
+       int (*notifier_add)(struct hvc_struct *hp, int irq);
+       void (*notifier_del)(struct hvc_struct *hp, int irq);
+};
 
 /* Register a vterm and a slot index for use as a console (console_init) */
 extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops);
 
 /* register a vterm for hvc tty operation (module_init or hotplug add) */
-extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq,
+extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data,
                                struct hv_ops *ops, int outbuf_size);
-/* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */
+/* remove a vterm from hvc tty operation (module_exit or hotplug remove) */
 extern int __devexit hvc_remove(struct hvc_struct *hp);
 
+/* data available */
+int hvc_poll(struct hvc_struct *hp);
+void hvc_kick(void);
+
+/* default notifier for irq based notification */
+extern int notifier_add_irq(struct hvc_struct *hp, int data);
+extern void notifier_del_irq(struct hvc_struct *hp, int data);
+
 
 #if defined(CONFIG_XMON) && defined(CONFIG_SMP)
 #include <asm/xmon.h>
 
--- /dev/null
+/*
+ * Copyright IBM Corp. 2001,2008
+ *
+ * This file contains the IRQ specific code for hvc_console
+ *
+ */
+
+#include <linux/interrupt.h>
+
+#include "hvc_console.h"
+
+static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance)
+{
+       /* if hvc_poll request a repoll, then kick the hvcd thread */
+       if (hvc_poll(dev_instance))
+               hvc_kick();
+       return IRQ_HANDLED;
+}
+
+/*
+ * For IRQ based systems these callbacks can be used
+ */
+int notifier_add_irq(struct hvc_struct *hp, int irq)
+{
+       int rc;
+
+       if (!irq) {
+               hp->irq_requested = 0;
+               return 0;
+       }
+       rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED,
+                          "hvc_console", hp);
+       if (!rc)
+               hp->irq_requested = 1;
+       return rc;
+}
+
+void notifier_del_irq(struct hvc_struct *hp, int irq)
+{
+       if (!irq)
+               return;
+       free_irq(irq, hp);
+       hp->irq_requested = 0;
+}