diff --git a/drivers/staging/gpib/common/Makefile b/drivers/staging/gpib/common/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..0c4c77bea75b3e14c8c79f2210ac057f0dc93589
--- /dev/null
+++ b/drivers/staging/gpib/common/Makefile
@@ -0,0 +1,6 @@
+
+obj-m += gpib_common.o
+
+gpib_common-objs := gpib_os.o iblib.o
+
+
diff --git a/drivers/staging/gpib/common/gpib_os.c b/drivers/staging/gpib/common/gpib_os.c
new file mode 100644
index 0000000000000000000000000000000000000000..d5860a0a131fec9e4acbc0bb08122e0d22151443
--- /dev/null
+++ b/drivers/staging/gpib/common/gpib_os.c
@@ -0,0 +1,2320 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/***************************************************************************
+ *    copyright            : (C) 2001, 2004 by Frank Mori Hess
+ ***************************************************************************
+ */
+
+#include "ibsys.h"
+#include <linux/module.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <linux/fcntl.h>
+#include <linux/kmod.h>
+#include <linux/uaccess.h>
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(GPIB_CODE);
+
+static int board_type_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board, unsigned long arg);
+static int read_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board,
+		      unsigned long arg);
+static int write_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board,
+		       unsigned long arg);
+static int command_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board,
+			 unsigned long arg);
+static int open_dev_ioctl(struct file *filep, gpib_board_t *board, unsigned long arg);
+static int close_dev_ioctl(struct file *filep, gpib_board_t *board, unsigned long arg);
+static int serial_poll_ioctl(gpib_board_t *board, unsigned long arg);
+static int wait_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board, unsigned long arg);
+static int parallel_poll_ioctl(gpib_board_t *board, unsigned long arg);
+static int online_ioctl(gpib_board_t *board, unsigned long arg);
+static int remote_enable_ioctl(gpib_board_t *board, unsigned long arg);
+static int take_control_ioctl(gpib_board_t *board, unsigned long arg);
+static int line_status_ioctl(gpib_board_t *board, unsigned long arg);
+static int pad_ioctl(gpib_board_t *board, gpib_file_private_t *file_priv,
+		     unsigned long arg);
+static int sad_ioctl(gpib_board_t *board, gpib_file_private_t *file_priv,
+		     unsigned long arg);
+static int eos_ioctl(gpib_board_t *board, unsigned long arg);
+static int request_service_ioctl(gpib_board_t *board, unsigned long arg);
+static int request_service2_ioctl(gpib_board_t *board, unsigned long arg);
+static int iobase_ioctl(gpib_board_config_t *config, unsigned long arg);
+static int irq_ioctl(gpib_board_config_t *config, unsigned long arg);
+static int dma_ioctl(gpib_board_config_t *config, unsigned long arg);
+static int autospoll_ioctl(gpib_board_t *board, gpib_file_private_t *file_priv,
+			   unsigned long arg);
+static int mutex_ioctl(gpib_board_t *board, gpib_file_private_t *file_priv,
+		       unsigned long arg);
+static int timeout_ioctl(gpib_board_t *board, unsigned long arg);
+static int status_bytes_ioctl(gpib_board_t *board, unsigned long arg);
+static int board_info_ioctl(const gpib_board_t *board, unsigned long arg);
+static int ppc_ioctl(gpib_board_t *board, unsigned long arg);
+static int set_local_ppoll_mode_ioctl(gpib_board_t *board, unsigned long arg);
+static int get_local_ppoll_mode_ioctl(gpib_board_t *board, unsigned long arg);
+static int query_board_rsv_ioctl(gpib_board_t *board, unsigned long arg);
+static int interface_clear_ioctl(gpib_board_t *board, unsigned long arg);
+static int select_pci_ioctl(gpib_board_config_t *config, unsigned long arg);
+static int select_device_path_ioctl(gpib_board_config_t *config, unsigned long arg);
+static int event_ioctl(gpib_board_t *board, unsigned long arg);
+static int request_system_control_ioctl(gpib_board_t *board, unsigned long arg);
+static int t1_delay_ioctl(gpib_board_t *board, unsigned long arg);
+
+static int cleanup_open_devices(gpib_file_private_t *file_priv, gpib_board_t *board);
+
+static int pop_gpib_event_nolock(gpib_event_queue_t *queue, short *event_type);
+
+/*
+ * Timer functions
+ */
+
+/* Watchdog timeout routine */
+
+static void watchdog_timeout(struct timer_list *t)
+{
+	gpib_board_t *board = from_timer(board, t, timer);
+
+	set_bit(TIMO_NUM, &board->status);
+	wake_up_interruptible(&board->wait);
+}
+
+/* install timer interrupt handler */
+void os_start_timer(gpib_board_t *board, unsigned int usec_timeout)
+/* Starts the timeout task  */
+{
+	if (timer_pending(&board->timer)) {
+		pr_err("gpib: bug! timer already running?\n");
+		return;
+	}
+	clear_bit(TIMO_NUM, &board->status);
+
+	if (usec_timeout > 0) {
+		board->timer.function = watchdog_timeout;
+		/* set number of ticks */
+		mod_timer(&board->timer, jiffies + usec_to_jiffies(usec_timeout));
+	}
+}
+
+void os_remove_timer(gpib_board_t *board)
+/* Removes the timeout task */
+{
+	if (timer_pending(&board->timer))
+		del_timer_sync(&board->timer);
+}
+
+int io_timed_out(gpib_board_t *board)
+{
+	if (test_bit(TIMO_NUM, &board->status))
+		return 1;
+	return 0;
+}
+
+void writeb_wrapper(unsigned int value, void *address)
+{
+	writeb(value, address);
+};
+EXPORT_SYMBOL(writeb_wrapper);
+
+void writew_wrapper(unsigned int value, void *address)
+{
+	writew(value, address);
+};
+EXPORT_SYMBOL(writew_wrapper);
+
+unsigned int readb_wrapper(void *address)
+{
+	return readb(address);
+};
+EXPORT_SYMBOL(readb_wrapper);
+
+unsigned int readw_wrapper(void *address)
+{
+	return readw(address);
+};
+EXPORT_SYMBOL(readw_wrapper);
+
+void outb_wrapper(unsigned int value, void *address)
+{
+	outb(value, (unsigned long)(address));
+};
+EXPORT_SYMBOL(outb_wrapper);
+
+void outw_wrapper(unsigned int value, void *address)
+{
+	outw(value, (unsigned long)(address));
+};
+EXPORT_SYMBOL(outw_wrapper);
+
+unsigned int inb_wrapper(void *address)
+{
+	return inb((unsigned long)(address));
+};
+EXPORT_SYMBOL(inb_wrapper);
+
+unsigned int inw_wrapper(void *address)
+{
+	return inw((unsigned long)(address));
+};
+EXPORT_SYMBOL(inw_wrapper);
+
+/* this is a function instead of a constant because of Suse
+ * defining HZ to be a function call to get_hz()
+ */
+static inline int pseudo_irq_period(void)
+{
+	return (HZ + 99) / 100;
+}
+
+static void pseudo_irq_handler(struct timer_list *t)
+{
+	struct gpib_pseudo_irq *pseudo_irq = from_timer(pseudo_irq, t, timer);
+
+	if (pseudo_irq->handler)
+		pseudo_irq->handler(0, pseudo_irq->board);
+	else
+		pr_err("gpib: bug! pseudo_irq.handler is NULL\n");
+
+	if (atomic_read(&pseudo_irq->active))
+		mod_timer(&pseudo_irq->timer, jiffies + pseudo_irq_period());
+}
+
+int gpib_request_pseudo_irq(gpib_board_t *board, irqreturn_t (*handler)(int, void *))
+{
+	if (timer_pending(&board->pseudo_irq.timer) || board->pseudo_irq.handler) {
+		pr_err("gpib: only one pseudo interrupt per board allowed\n");
+		return -1;
+	}
+
+	board->pseudo_irq.handler = handler;
+	board->pseudo_irq.timer.function = pseudo_irq_handler;
+	board->pseudo_irq.board = board;
+
+	atomic_set(&board->pseudo_irq.active, 1);
+
+	mod_timer(&board->pseudo_irq.timer, jiffies + pseudo_irq_period());
+
+	return 0;
+}
+EXPORT_SYMBOL(gpib_request_pseudo_irq);
+
+void gpib_free_pseudo_irq(gpib_board_t *board)
+{
+	atomic_set(&board->pseudo_irq.active, 0);
+
+	del_timer_sync(&board->pseudo_irq.timer);
+	board->pseudo_irq.handler = NULL;
+}
+EXPORT_SYMBOL(gpib_free_pseudo_irq);
+
+static const unsigned int serial_timeout = 1000000;
+
+unsigned int num_status_bytes(const gpib_status_queue_t *dev)
+{
+	if (!dev)
+		return 0;
+	return dev->num_status_bytes;
+}
+
+// push status byte onto back of status byte fifo
+int push_status_byte(gpib_status_queue_t *device, u8 poll_byte)
+{
+	struct list_head *head = &device->status_bytes;
+	status_byte_t *status;
+	static const unsigned int max_num_status_bytes = 1024;
+	int retval;
+
+	if (num_status_bytes(device) >= max_num_status_bytes) {
+		u8 lost_byte;
+
+		device->dropped_byte = 1;
+		retval = pop_status_byte(device, &lost_byte);
+		if (retval < 0)
+			return retval;
+	}
+
+	status = kmalloc(sizeof(status_byte_t), GFP_KERNEL);
+	if (!status)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&status->list);
+	status->poll_byte = poll_byte;
+
+	list_add_tail(&status->list, head);
+
+	device->num_status_bytes++;
+
+	GPIB_DPRINTK("pushed status byte 0x%x, %i in queue\n",
+		     (int)poll_byte, num_status_bytes(device));
+
+	return 0;
+}
+
+// pop status byte from front of status byte fifo
+int pop_status_byte(gpib_status_queue_t *device, u8 *poll_byte)
+{
+	struct list_head *head = &device->status_bytes;
+	struct list_head *front = head->next;
+	status_byte_t *status;
+
+	if (num_status_bytes(device) == 0)
+		return -EIO;
+
+	if (front == head)
+		return -EIO;
+
+	if (device->dropped_byte) {
+		device->dropped_byte = 0;
+		return -EPIPE;
+	}
+
+	status = list_entry(front, status_byte_t, list);
+	*poll_byte = status->poll_byte;
+
+	list_del(front);
+	kfree(status);
+
+	device->num_status_bytes--;
+
+	GPIB_DPRINTK("popped status byte 0x%x, %i in queue\n",
+		     (int)*poll_byte, num_status_bytes(device));
+
+	return 0;
+}
+
+gpib_status_queue_t *get_gpib_status_queue(gpib_board_t *board, unsigned int pad, int sad)
+{
+	gpib_status_queue_t *device;
+	struct list_head *list_ptr;
+	const struct list_head *head = &board->device_list;
+
+	for (list_ptr = head->next; list_ptr != head; list_ptr = list_ptr->next) {
+		device = list_entry(list_ptr, gpib_status_queue_t, list);
+		if (gpib_address_equal(device->pad, device->sad, pad, sad))
+			return device;
+	}
+
+	return NULL;
+}
+
+int get_serial_poll_byte(gpib_board_t *board, unsigned int pad, int sad, unsigned int usec_timeout,
+			 uint8_t *poll_byte)
+{
+	gpib_status_queue_t *device;
+
+	GPIB_DPRINTK("%s:()\n", __func__);
+
+	device = get_gpib_status_queue(board, pad, sad);
+	if (num_status_bytes(device))
+		return pop_status_byte(device, poll_byte);
+	else
+		return dvrsp(board, pad, sad, usec_timeout, poll_byte);
+}
+
+int autopoll_all_devices(gpib_board_t *board)
+{
+	int retval;
+
+	GPIB_DPRINTK("entering %s()\n", __func__);
+	if (mutex_lock_interruptible(&board->user_mutex))
+		return -ERESTARTSYS;
+	if (mutex_lock_interruptible(&board->big_gpib_mutex)) {
+		mutex_unlock(&board->user_mutex);
+		return -ERESTARTSYS;
+	}
+
+	GPIB_DPRINTK("autopoll has board lock\n");
+
+	retval = serial_poll_all(board, serial_timeout);
+	if (retval < 0)	{
+		mutex_unlock(&board->big_gpib_mutex);
+		mutex_unlock(&board->user_mutex);
+		return retval;
+	}
+
+	GPIB_DPRINTK("%s complete\n", __func__);
+	/* need to wake wait queue in case someone is
+	 * waiting on RQS
+	 */
+	wake_up_interruptible(&board->wait);
+	mutex_unlock(&board->big_gpib_mutex);
+	mutex_unlock(&board->user_mutex);
+
+	return retval;
+}
+
+static int setup_serial_poll(gpib_board_t *board, unsigned int usec_timeout)
+{
+	u8 cmd_string[8];
+	int i;
+	size_t bytes_written;
+	int ret;
+
+	GPIB_DPRINTK("entering %s()\n", __func__);
+
+	os_start_timer(board, usec_timeout);
+	ret = ibcac(board, 1, 1);
+	if (ret < 0) {
+		os_remove_timer(board);
+		return ret;
+	}
+
+	i = 0;
+	cmd_string[i++] = UNL;
+	cmd_string[i++] = MLA(board->pad);	/* controller's listen address */
+	if (board->sad >= 0)
+		cmd_string[i++] = MSA(board->sad);
+	cmd_string[i++] = SPE;	//serial poll enable
+
+	ret = board->interface->command(board, cmd_string, i, &bytes_written);
+	if (ret < 0 || bytes_written < i) {
+		pr_err("gpib: failed to setup serial poll\n");
+		os_remove_timer(board);
+		return -EIO;
+	}
+	os_remove_timer(board);
+
+	return 0;
+}
+
+static int read_serial_poll_byte(gpib_board_t *board, unsigned int pad,
+				 int sad, unsigned int usec_timeout, uint8_t *result)
+{
+	u8 cmd_string[8];
+	int end_flag;
+	int ret;
+	int i;
+	size_t nbytes;
+
+	GPIB_DPRINTK("entering %s(), pad=%i sad=%i\n", __func__, pad, sad);
+
+	os_start_timer(board, usec_timeout);
+	ret = ibcac(board, 1, 1);
+	if (ret < 0) {
+		os_remove_timer(board);
+		return ret;
+	}
+
+	i = 0;
+	// send talk address
+	cmd_string[i++] = MTA(pad);
+	if (sad >= 0)
+		cmd_string[i++] = MSA(sad);
+
+	ret = board->interface->command(board, cmd_string, i, &nbytes);
+	if (ret < 0 || nbytes < i) {
+		pr_err("gpib: failed to setup serial poll\n");
+		os_remove_timer(board);
+		return -EIO;
+	}
+
+	ibgts(board);
+
+	// read poll result
+	ret = board->interface->read(board, result, 1, &end_flag, &nbytes);
+	if (ret < 0 || nbytes < 1) {
+		pr_err("gpib: serial poll failed\n");
+		os_remove_timer(board);
+		return -EIO;
+	}
+	os_remove_timer(board);
+
+	return 0;
+}
+
+static int cleanup_serial_poll(gpib_board_t *board, unsigned int usec_timeout)
+{
+	u8 cmd_string[8];
+	int ret;
+	size_t bytes_written;
+
+	GPIB_DPRINTK("entering %s()\n", __func__);
+
+	os_start_timer(board, usec_timeout);
+	ret = ibcac(board, 1, 1);
+	if (ret < 0) {
+		os_remove_timer(board);
+		return ret;
+	}
+
+	cmd_string[0] = SPD;	/* disable serial poll bytes */
+	cmd_string[1] = UNT;
+	ret = board->interface->command(board, cmd_string, 2, &bytes_written);
+	if (ret < 0 || bytes_written < 2) {
+		pr_err("gpib: failed to disable serial poll\n");
+		os_remove_timer(board);
+		return -EIO;
+	}
+	os_remove_timer(board);
+
+	return 0;
+}
+
+static int serial_poll_single(gpib_board_t *board, unsigned int pad, int sad,
+			      unsigned int usec_timeout, uint8_t *result)
+{
+	int retval, cleanup_retval;
+
+	retval = setup_serial_poll(board, usec_timeout);
+	if (retval < 0)
+		return retval;
+	retval = read_serial_poll_byte(board, pad, sad, usec_timeout, result);
+	cleanup_retval = cleanup_serial_poll(board, usec_timeout);
+	if (retval < 0)
+		return retval;
+	if (cleanup_retval < 0)
+		return retval;
+
+	return 0;
+}
+
+int serial_poll_all(gpib_board_t *board, unsigned int usec_timeout)
+{
+	int retval = 0;
+	struct list_head *cur;
+	const struct list_head *head = NULL;
+	gpib_status_queue_t *device;
+	u8 result;
+	unsigned int num_bytes = 0;
+
+	GPIB_DPRINTK("entering %s()\n", __func__);
+
+	head = &board->device_list;
+	if (head->next == head)
+		return 0;
+
+	retval = setup_serial_poll(board, usec_timeout);
+	if (retval < 0)
+		return retval;
+
+	for (cur = head->next; cur != head; cur = cur->next) {
+		device = list_entry(cur, gpib_status_queue_t, list);
+		retval = read_serial_poll_byte(board,
+					       device->pad, device->sad, usec_timeout, &result);
+		if (retval < 0)
+			continue;
+		if (result & request_service_bit) {
+			retval = push_status_byte(device, result);
+			if (retval < 0)
+				continue;
+			num_bytes++;
+		}
+	}
+
+	retval = cleanup_serial_poll(board, usec_timeout);
+	if (retval < 0)
+		return retval;
+
+	return num_bytes;
+}
+
+/*
+ * DVRSP
+ * This function performs a serial poll of the device with primary
+ * address pad and secondary address sad. If the device has no
+ * secondary address, pass a negative number in for this argument.  At the
+ * end of a successful serial poll the response is returned in result.
+ * SPD and UNT are sent at the completion of the poll.
+ */
+
+int dvrsp(gpib_board_t *board, unsigned int pad, int sad,
+	  unsigned int usec_timeout, uint8_t *result)
+{
+	int status = ibstatus(board);
+	int retval;
+
+	if ((status & CIC) == 0) {
+		pr_err("gpib: not CIC during serial poll\n");
+		return -1;
+	}
+
+	if (pad > gpib_addr_max || sad > gpib_addr_max) {
+		pr_err("gpib: bad address for serial poll");
+		return -1;
+	}
+
+	retval = serial_poll_single(board, pad, sad, usec_timeout, result);
+	if (io_timed_out(board))
+		retval = -ETIMEDOUT;
+
+	return retval;
+}
+
+static gpib_descriptor_t *handle_to_descriptor(const gpib_file_private_t *file_priv,
+					       int handle)
+{
+	if (handle < 0 || handle >= GPIB_MAX_NUM_DESCRIPTORS) {
+		pr_err("gpib: invalid handle %i\n", handle);
+		return NULL;
+	}
+
+	return file_priv->descriptors[handle];
+}
+
+static int init_gpib_file_private(gpib_file_private_t *priv)
+{
+	memset(priv, 0, sizeof(*priv));
+	atomic_set(&priv->holding_mutex, 0);
+	priv->descriptors[0] = kmalloc(sizeof(gpib_descriptor_t), GFP_KERNEL);
+	if (!priv->descriptors[0]) {
+		pr_err("gpib: failed to allocate default board descriptor\n");
+		return -ENOMEM;
+	}
+	init_gpib_descriptor(priv->descriptors[0]);
+	priv->descriptors[0]->is_board = 1;
+	mutex_init(&priv->descriptors_mutex);
+	return 0;
+}
+
+int ibopen(struct inode *inode, struct file *filep)
+{
+	unsigned int minor = iminor(inode);
+	gpib_board_t *board;
+	gpib_file_private_t *priv;
+
+	if (minor >= GPIB_MAX_NUM_BOARDS) {
+		pr_err("gpib: invalid minor number of device file\n");
+		return -ENXIO;
+	}
+
+	board = &board_array[minor];
+
+	filep->private_data = kmalloc(sizeof(gpib_file_private_t), GFP_KERNEL);
+	if (!filep->private_data)
+		return -ENOMEM;
+
+	priv = filep->private_data;
+	init_gpib_file_private((gpib_file_private_t *)filep->private_data);
+
+	GPIB_DPRINTK("pid %i, gpib: opening minor %d\n", current->pid, minor);
+
+	if (board->use_count == 0) {
+		char module_string[32];
+		int retval;
+
+		snprintf(module_string, sizeof(module_string), "gpib%i", minor);
+		retval = request_module(module_string);
+		if (retval) {
+			GPIB_DPRINTK("pid %i, gpib: request module returned %i\n",
+				     current->pid, retval);
+		}
+	}
+	if (board->interface) {
+		if (!try_module_get(board->provider_module)) {
+			pr_err("gpib: try_module_get() failed\n");
+			return -EIO;
+		}
+		board->use_count++;
+		priv->got_module = 1;
+	}
+	return 0;
+}
+
+int ibclose(struct inode *inode, struct file *filep)
+{
+	unsigned int minor = iminor(inode);
+	gpib_board_t *board;
+	gpib_file_private_t *priv = filep->private_data;
+	gpib_descriptor_t *desc;
+
+	if (minor >= GPIB_MAX_NUM_BOARDS) {
+		pr_err("gpib: invalid minor number of device file\n");
+		return -ENODEV;
+	}
+
+	GPIB_DPRINTK("pid %i, gpib: closing minor %d\n", current->pid, minor);
+
+	board = &board_array[minor];
+
+	if (priv) {
+		desc = handle_to_descriptor(priv, 0);
+		if (desc) {
+			if (desc->autopoll_enabled) {
+				GPIB_DPRINTK("pid %i, gpib: decrementing autospollers\n",
+					     current->pid);
+				if (board->autospollers > 0)
+					board->autospollers--;
+				else
+					pr_err("gpib: Attempt to decrement zero autospollers\n");
+			}
+		} else {
+			pr_err("gpib: Unexpected null gpib_descriptor\n");
+		}
+
+		cleanup_open_devices(priv, board);
+
+		if (atomic_read(&priv->holding_mutex))
+			mutex_unlock(&board->user_mutex);
+
+		if (priv->got_module && board->use_count) {
+			module_put(board->provider_module);
+			--board->use_count;
+		}
+
+		kfree(filep->private_data);
+		filep->private_data = NULL;
+	}
+
+	return 0;
+}
+
+long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+	unsigned int minor = iminor(filep->f_path.dentry->d_inode);
+	gpib_board_t *board;
+	gpib_file_private_t *file_priv = filep->private_data;
+	long retval = -ENOTTY;
+
+	if (minor >= GPIB_MAX_NUM_BOARDS) {
+		pr_err("gpib: invalid minor number of device file\n");
+		return -ENODEV;
+	}
+	board = &board_array[minor];
+
+	if (mutex_lock_interruptible(&board->big_gpib_mutex))
+		return -ERESTARTSYS;
+
+	GPIB_DPRINTK("pid %i, minor %i, ioctl %d, interface=%s, use=%d, onl=%d\n",
+		     current->pid, minor, cmd & 0xff,
+		     board->interface ? board->interface->name : "",
+		     board->use_count,
+		     board->online);
+
+	switch (cmd) {
+	case CFCBOARDTYPE:
+		retval = board_type_ioctl(file_priv, board, arg);
+		goto done;
+	case IBONL:
+		retval = online_ioctl(board, arg);
+		goto done;
+	default:
+		break;
+	}
+	if (!board->interface) {
+		pr_err("gpib: no gpib board configured on /dev/gpib%i\n", minor);
+		retval = -ENODEV;
+		goto done;
+	}
+	if (file_priv->got_module == 0)	{
+		if (!try_module_get(board->provider_module)) {
+			pr_err("gpib: try_module_get() failed\n");
+			retval = -EIO;
+			goto done;
+		}
+		file_priv->got_module = 1;
+		board->use_count++;
+	}
+	switch (cmd) {
+	case CFCBASE:
+		retval = iobase_ioctl(&board->config, arg);
+		goto done;
+	case CFCIRQ:
+		retval = irq_ioctl(&board->config, arg);
+		goto done;
+	case CFCDMA:
+		retval = dma_ioctl(&board->config, arg);
+		goto done;
+	case IBAUTOSPOLL:
+		retval = autospoll_ioctl(board, file_priv, arg);
+		goto done;
+	case IBBOARD_INFO:
+		retval = board_info_ioctl(board, arg);
+		goto done;
+	case IBMUTEX:
+		/* Need to unlock board->big_gpib_mutex before potentially locking board->user_mutex
+		 *  to maintain consistent locking order
+		 */
+		mutex_unlock(&board->big_gpib_mutex);
+		return mutex_ioctl(board, file_priv, arg);
+	case IBPAD:
+		retval = pad_ioctl(board, file_priv, arg);
+		goto done;
+	case IBSAD:
+		retval = sad_ioctl(board, file_priv, arg);
+		goto done;
+	case IBSELECT_PCI:
+		retval = select_pci_ioctl(&board->config, arg);
+		goto done;
+	case IBSELECT_DEVICE_PATH:
+		retval = select_device_path_ioctl(&board->config, arg);
+		goto done;
+	default:
+		break;
+	}
+
+	if (!board->online) {
+		pr_err("gpib: ioctl %i invalid for offline board\n",
+		       cmd & 0xff);
+		retval = -EINVAL;
+		goto done;
+	}
+
+	switch (cmd) {
+	case IBEVENT:
+		retval = event_ioctl(board, arg);
+		goto done;
+	case IBCLOSEDEV:
+		retval = close_dev_ioctl(filep, board, arg);
+		goto done;
+	case IBOPENDEV:
+		retval = open_dev_ioctl(filep, board, arg);
+		goto done;
+	case IBSPOLL_BYTES:
+		retval = status_bytes_ioctl(board, arg);
+		goto done;
+	case IBWAIT:
+		retval = wait_ioctl(file_priv, board, arg);
+		if (retval == -ERESTARTSYS)
+			return retval;
+		goto done;
+	case IBLINES:
+		retval = line_status_ioctl(board, arg);
+		goto done;
+	case IBLOC:
+		board->interface->return_to_local(board);
+		retval = 0;
+		goto done;
+	default:
+		break;
+	}
+
+	spin_lock(&board->locking_pid_spinlock);
+	if (current->pid != board->locking_pid)	{
+		spin_unlock(&board->locking_pid_spinlock);
+		pr_err("gpib: need to hold board lock to perform ioctl %i\n",
+		       cmd & 0xff);
+		retval = -EPERM;
+		goto done;
+	}
+	spin_unlock(&board->locking_pid_spinlock);
+
+	switch (cmd) {
+	case IB_T1_DELAY:
+		retval = t1_delay_ioctl(board, arg);
+		goto done;
+	case IBCAC:
+		retval = take_control_ioctl(board, arg);
+		goto done;
+	case IBCMD:
+		/* IO ioctls can take a long time, we need to unlock board->big_gpib_mutex
+		 *  before we call them.
+		 */
+		mutex_unlock(&board->big_gpib_mutex);
+		return command_ioctl(file_priv, board, arg);
+	case IBEOS:
+		retval = eos_ioctl(board, arg);
+		goto done;
+	case IBGTS:
+		retval = ibgts(board);
+		goto done;
+	case IBPPC:
+		retval = ppc_ioctl(board, arg);
+		goto done;
+	case IBPP2_SET:
+		retval = set_local_ppoll_mode_ioctl(board, arg);
+		goto done;
+	case IBPP2_GET:
+		retval = get_local_ppoll_mode_ioctl(board, arg);
+		goto done;
+	case IBQUERY_BOARD_RSV:
+		retval = query_board_rsv_ioctl(board, arg);
+		goto done;
+	case IBRD:
+		/* IO ioctls can take a long time, we need to unlock board->big_gpib_mutex
+		 *  before we call them.
+		 */
+		mutex_unlock(&board->big_gpib_mutex);
+		return read_ioctl(file_priv, board, arg);
+	case IBRPP:
+		retval = parallel_poll_ioctl(board, arg);
+		goto done;
+	case IBRSC:
+		retval = request_system_control_ioctl(board, arg);
+		goto done;
+	case IBRSP:
+		retval = serial_poll_ioctl(board, arg);
+		goto done;
+	case IBRSV:
+		retval = request_service_ioctl(board, arg);
+		goto done;
+	case IBRSV2:
+		retval = request_service2_ioctl(board, arg);
+		goto done;
+	case IBSIC:
+		retval = interface_clear_ioctl(board, arg);
+		goto done;
+	case IBSRE:
+		retval = remote_enable_ioctl(board, arg);
+		goto done;
+	case IBTMO:
+		retval = timeout_ioctl(board, arg);
+		goto done;
+	case IBWRT:
+		/* IO ioctls can take a long time, we need to unlock board->big_gpib_mutex
+		 *  before we call them.
+		 */
+		mutex_unlock(&board->big_gpib_mutex);
+		return write_ioctl(file_priv, board, arg);
+	default:
+		retval = -ENOTTY;
+		goto done;
+	}
+
+done:
+	mutex_unlock(&board->big_gpib_mutex);
+	GPIB_DPRINTK("ioctl done status = 0x%lx\n", board->status);
+	return retval;
+}
+
+static int board_type_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board, unsigned long arg)
+{
+	struct list_head *list_ptr;
+	board_type_ioctl_t cmd;
+	int retval;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (board->online) {
+		pr_err("gpib: can't change board type while board is online.\n");
+		return -EBUSY;
+	}
+
+	retval = copy_from_user(&cmd, (void *)arg, sizeof(board_type_ioctl_t));
+	if (retval)
+		return retval;
+
+	for (list_ptr = registered_drivers.next; list_ptr != &registered_drivers;
+	     list_ptr = list_ptr->next) {
+		gpib_interface_list_t *entry;
+
+		entry = list_entry(list_ptr, gpib_interface_list_t, list);
+		if (strcmp(entry->interface->name, cmd.name) == 0) {
+			int i;
+			int had_module = file_priv->got_module;
+
+			if (board->use_count) {
+				for (i = 0; i < board->use_count; ++i)
+					module_put(board->provider_module);
+				board->interface = NULL;
+				file_priv->got_module = 0;
+			}
+			board->interface = entry->interface;
+			board->provider_module = entry->module;
+			for (i = 0; i < board->use_count; ++i) {
+				if (!try_module_get(entry->module)) {
+					board->use_count = i;
+					return -EIO;
+				}
+			}
+			if (had_module == 0) {
+				if (!try_module_get(entry->module))
+					return -EIO;
+				++board->use_count;
+			}
+			file_priv->got_module = 1;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int read_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board,
+		      unsigned long arg)
+{
+	read_write_ioctl_t read_cmd;
+	u8 *userbuf;
+	unsigned long remain;
+	int end_flag = 0;
+	int retval;
+	ssize_t read_ret = 0;
+	gpib_descriptor_t *desc;
+	size_t nbytes;
+
+	retval = copy_from_user(&read_cmd, (void *)arg, sizeof(read_cmd));
+	if (retval)
+		return -EFAULT;
+
+	if (read_cmd.completed_transfer_count > read_cmd.requested_transfer_count)
+		return -EINVAL;
+
+	desc = handle_to_descriptor(file_priv, read_cmd.handle);
+	if (!desc)
+		return -EINVAL;
+
+	if (WARN_ON_ONCE(sizeof(userbuf) > sizeof(read_cmd.buffer_ptr)))
+		return -EFAULT;
+
+	userbuf = (u8 *)(unsigned long)read_cmd.buffer_ptr;
+	userbuf += read_cmd.completed_transfer_count;
+
+	remain = read_cmd.requested_transfer_count - read_cmd.completed_transfer_count;
+
+	/* Check write access to buffer */
+	if (!access_ok(userbuf, remain))
+		return -EFAULT;
+
+	atomic_set(&desc->io_in_progress, 1);
+
+	/* Read buffer loads till we fill the user supplied buffer */
+	while (remain > 0 && end_flag == 0) {
+		nbytes = 0;
+		read_ret = ibrd(board, board->buffer, (board->buffer_length < remain) ?
+				board->buffer_length : remain, &end_flag, &nbytes);
+		if (nbytes == 0)
+			break;
+		retval = copy_to_user(userbuf, board->buffer, nbytes);
+		if (retval) {
+			retval = -EFAULT;
+			break;
+		}
+		remain -= nbytes;
+		userbuf += nbytes;
+		if (read_ret < 0)
+			break;
+	}
+	read_cmd.completed_transfer_count = read_cmd.requested_transfer_count - remain;
+	read_cmd.end = end_flag;
+	/* suppress errors (for example due to timeout or interruption by device clear)
+	 * if all bytes got sent.  This prevents races that can occur in the various drivers
+	 * if a device receives a device clear immediately after a transfer completes and
+	 * the driver code wasn't careful enough to handle that case.
+	 */
+	if (remain == 0 || end_flag)
+		read_ret = 0;
+	if (retval == 0)
+		retval = copy_to_user((void *)arg, &read_cmd, sizeof(read_cmd));
+
+	atomic_set(&desc->io_in_progress, 0);
+
+	wake_up_interruptible(&board->wait);
+	if (retval)
+		return -EFAULT;
+
+	return read_ret;
+}
+
+static int command_ioctl(gpib_file_private_t *file_priv,
+			 gpib_board_t *board, unsigned long arg)
+{
+	read_write_ioctl_t cmd;
+	u8 *userbuf;
+	unsigned long remain;
+	int retval;
+	int fault = 0;
+	gpib_descriptor_t *desc;
+	size_t bytes_written;
+	int no_clear_io_in_prog;
+
+	retval = copy_from_user(&cmd, (void *)arg, sizeof(cmd));
+	if (retval)
+		return -EFAULT;
+
+	if (cmd.completed_transfer_count > cmd.requested_transfer_count)
+		return -EINVAL;
+
+	desc = handle_to_descriptor(file_priv, cmd.handle);
+	if (!desc)
+		return -EINVAL;
+
+	userbuf = (u8 *)(unsigned long)cmd.buffer_ptr;
+	userbuf += cmd.completed_transfer_count;
+
+	no_clear_io_in_prog = cmd.end;
+	cmd.end = 0;
+
+	remain = cmd.requested_transfer_count - cmd.completed_transfer_count;
+
+	/* Check read access to buffer */
+	if (!access_ok(userbuf, remain))
+		return -EFAULT;
+
+	/* Write buffer loads till we empty the user supplied buffer.
+	 *	Call drivers at least once, even if remain is zero, in
+	 *	order to allow them to insure previous commands were
+	 *	completely finished, in the case of a restarted ioctl.
+	 */
+
+	atomic_set(&desc->io_in_progress, 1);
+
+	do {
+		fault = copy_from_user(board->buffer, userbuf, (board->buffer_length < remain) ?
+				       board->buffer_length : remain);
+		if (fault) {
+			retval = -EFAULT;
+			bytes_written = 0;
+		} else {
+			retval = ibcmd(board, board->buffer, (board->buffer_length < remain) ?
+				       board->buffer_length : remain, &bytes_written);
+		}
+		remain -= bytes_written;
+		userbuf += bytes_written;
+		if (retval < 0) {
+			atomic_set(&desc->io_in_progress, 0);
+
+			wake_up_interruptible(&board->wait);
+			break;
+		}
+	} while (remain > 0);
+
+	cmd.completed_transfer_count = cmd.requested_transfer_count - remain;
+
+	if (fault == 0)
+		fault = copy_to_user((void *)arg, &cmd, sizeof(cmd));
+
+	/*
+	 * no_clear_io_in_prog (cmd.end) is true when io_in_progress should
+	 * not be set to zero because the cmd in progress is the address setup
+	 * operation for an async read or write. This causes CMPL not to be set
+	 * in general_ibstatus until the async read or write completes.
+	 */
+	if (!no_clear_io_in_prog || fault)
+		atomic_set(&desc->io_in_progress, 0);
+
+	wake_up_interruptible(&board->wait);
+	if (fault)
+		return -EFAULT;
+
+	return retval;
+}
+
+static int write_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board,
+		       unsigned long arg)
+{
+	read_write_ioctl_t write_cmd;
+	u8 *userbuf;
+	unsigned long remain;
+	int retval = 0;
+	int fault;
+	gpib_descriptor_t *desc;
+
+	fault = copy_from_user(&write_cmd, (void *)arg, sizeof(write_cmd));
+	if (fault)
+		return -EFAULT;
+
+	if (write_cmd.completed_transfer_count > write_cmd.requested_transfer_count)
+		return -EINVAL;
+
+	desc = handle_to_descriptor(file_priv, write_cmd.handle);
+	if (!desc)
+		return -EINVAL;
+
+	userbuf = (u8 *)(unsigned long)write_cmd.buffer_ptr;
+	userbuf += write_cmd.completed_transfer_count;
+
+	remain = write_cmd.requested_transfer_count - write_cmd.completed_transfer_count;
+
+	/* Check read access to buffer */
+	if (!access_ok(userbuf, remain))
+		return -EFAULT;
+
+	atomic_set(&desc->io_in_progress, 1);
+
+	/* Write buffer loads till we empty the user supplied buffer */
+	while (remain > 0) {
+		int send_eoi;
+		size_t bytes_written = 0;
+
+		send_eoi = remain <= board->buffer_length && write_cmd.end;
+		fault = copy_from_user(board->buffer, userbuf, (board->buffer_length < remain) ?
+				       board->buffer_length : remain);
+		if (fault) {
+			retval = -EFAULT;
+			break;
+		}
+		retval = ibwrt(board, board->buffer, (board->buffer_length < remain) ?
+			       board->buffer_length : remain, send_eoi, &bytes_written);
+		remain -= bytes_written;
+		userbuf += bytes_written;
+		if (retval < 0)
+			break;
+	}
+	write_cmd.completed_transfer_count = write_cmd.requested_transfer_count - remain;
+	/* suppress errors (for example due to timeout or interruption by device clear)
+	 * if all bytes got sent.  This prevents races that can occur in the various drivers
+	 * if a device receives a device clear immediately after a transfer completes and
+	 * the driver code wasn't careful enough to handle that case.
+	 */
+	if (remain == 0)
+		retval = 0;
+	if (fault == 0)
+		fault = copy_to_user((void *)arg, &write_cmd, sizeof(write_cmd));
+
+	atomic_set(&desc->io_in_progress, 0);
+
+	wake_up_interruptible(&board->wait);
+	if (fault)
+		return -EFAULT;
+
+	return retval;
+}
+
+static int status_bytes_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	gpib_status_queue_t *device;
+	spoll_bytes_ioctl_t cmd;
+	int retval;
+
+	retval = copy_from_user(&cmd, (void *)arg, sizeof(cmd));
+	if (retval)
+		return -EFAULT;
+
+	device = get_gpib_status_queue(board, cmd.pad, cmd.sad);
+	if (!device)
+		cmd.num_bytes = 0;
+	else
+		cmd.num_bytes = num_status_bytes(device);
+
+	retval = copy_to_user((void *)arg, &cmd, sizeof(cmd));
+	if (retval)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int increment_open_device_count(struct list_head *head, unsigned int pad, int sad)
+{
+	struct list_head *list_ptr;
+	gpib_status_queue_t *device;
+
+	/* first see if address has already been opened, then increment
+	 * open count
+	 */
+	for (list_ptr = head->next; list_ptr != head; list_ptr = list_ptr->next) {
+		device = list_entry(list_ptr, gpib_status_queue_t, list);
+		if (gpib_address_equal(device->pad, device->sad, pad, sad)) {
+			GPIB_DPRINTK("pid %i, incrementing open count for pad %i, sad %i\n",
+				     current->pid, device->pad, device->sad);
+			device->reference_count++;
+			return 0;
+		}
+	}
+
+	/* otherwise we need to allocate a new gpib_status_queue_t */
+	device = kmalloc(sizeof(gpib_status_queue_t), GFP_ATOMIC);
+	if (!device)
+		return -ENOMEM;
+	init_gpib_status_queue(device);
+	device->pad = pad;
+	device->sad = sad;
+	device->reference_count = 1;
+
+	list_add(&device->list, head);
+
+	GPIB_DPRINTK("pid %i, opened pad %i, sad %i\n",
+		     current->pid, device->pad, device->sad);
+
+	return 0;
+}
+
+static int subtract_open_device_count(struct list_head *head, unsigned int pad, int sad,
+				      unsigned int count)
+{
+	gpib_status_queue_t *device;
+	struct list_head *list_ptr;
+
+	for (list_ptr = head->next; list_ptr != head; list_ptr = list_ptr->next) {
+		device = list_entry(list_ptr, gpib_status_queue_t, list);
+		if (gpib_address_equal(device->pad, device->sad, pad, sad)) {
+			GPIB_DPRINTK("pid %i, decrementing open count for pad %i, sad %i\n",
+				     current->pid, device->pad, device->sad);
+			if (count > device->reference_count) {
+				pr_err("gpib: bug! in %s()\n", __func__);
+				return -EINVAL;
+			}
+			device->reference_count -= count;
+			if (device->reference_count == 0) {
+				GPIB_DPRINTK("pid %i, closing pad %i, sad %i\n",
+					     current->pid, device->pad, device->sad);
+				list_del(list_ptr);
+				kfree(device);
+			}
+			return 0;
+		}
+	}
+	pr_err("gpib: bug! tried to close address that was never opened!\n");
+	return -EINVAL;
+}
+
+static inline int decrement_open_device_count(struct list_head *head, unsigned int pad, int sad)
+{
+	return subtract_open_device_count(head, pad, sad, 1);
+}
+
+static int cleanup_open_devices(gpib_file_private_t *file_priv, gpib_board_t *board)
+{
+	int retval = 0;
+	int i;
+
+	for (i = 0; i < GPIB_MAX_NUM_DESCRIPTORS; i++) {
+		gpib_descriptor_t *desc;
+
+		desc = file_priv->descriptors[i];
+		if (!desc)
+			continue;
+
+		if (desc->is_board == 0) {
+			retval = decrement_open_device_count(&board->device_list, desc->pad,
+							     desc->sad);
+			if (retval < 0)
+				return retval;
+		}
+		kfree(desc);
+		file_priv->descriptors[i] = NULL;
+	}
+
+	return 0;
+}
+
+static int open_dev_ioctl(struct file *filep, gpib_board_t *board, unsigned long arg)
+{
+	open_dev_ioctl_t open_dev_cmd;
+	int retval;
+	gpib_file_private_t *file_priv = filep->private_data;
+	int i;
+
+	retval = copy_from_user(&open_dev_cmd, (void *)arg, sizeof(open_dev_cmd));
+	if (retval)
+		return -EFAULT;
+
+	if (mutex_lock_interruptible(&file_priv->descriptors_mutex))
+		return -ERESTARTSYS;
+	for (i = 0; i < GPIB_MAX_NUM_DESCRIPTORS; i++)
+		if (!file_priv->descriptors[i])
+			break;
+	if (i == GPIB_MAX_NUM_DESCRIPTORS) {
+		mutex_unlock(&file_priv->descriptors_mutex);
+		return -ERANGE;
+	}
+	file_priv->descriptors[i] = kmalloc(sizeof(gpib_descriptor_t), GFP_KERNEL);
+	if (!file_priv->descriptors[i]) {
+		mutex_unlock(&file_priv->descriptors_mutex);
+		return -ENOMEM;
+	}
+	init_gpib_descriptor(file_priv->descriptors[i]);
+
+	file_priv->descriptors[i]->pad = open_dev_cmd.pad;
+	file_priv->descriptors[i]->sad = open_dev_cmd.sad;
+	file_priv->descriptors[i]->is_board = open_dev_cmd.is_board;
+	mutex_unlock(&file_priv->descriptors_mutex);
+
+	retval = increment_open_device_count(&board->device_list, open_dev_cmd.pad,
+					     open_dev_cmd.sad);
+	if (retval < 0)
+		return retval;
+
+	/* clear stuck srq state, since we may be able to find service request on
+	 * the new device
+	 */
+	atomic_set(&board->stuck_srq, 0);
+
+	open_dev_cmd.handle = i;
+	retval = copy_to_user((void *)arg, &open_dev_cmd, sizeof(open_dev_cmd));
+	if (retval)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int close_dev_ioctl(struct file *filep, gpib_board_t *board, unsigned long arg)
+{
+	close_dev_ioctl_t cmd;
+	gpib_file_private_t *file_priv = filep->private_data;
+	int retval;
+
+	retval = copy_from_user(&cmd, (void *)arg, sizeof(cmd));
+	if (retval)
+		return -EFAULT;
+
+	if (cmd.handle >= GPIB_MAX_NUM_DESCRIPTORS)
+		return -EINVAL;
+	if (!file_priv->descriptors[cmd.handle])
+		return -EINVAL;
+
+	retval = decrement_open_device_count(&board->device_list,
+					     file_priv->descriptors[cmd.handle]->pad,
+					     file_priv->descriptors[cmd.handle]->sad);
+	if (retval < 0)
+		return retval;
+
+	kfree(file_priv->descriptors[cmd.handle]);
+	file_priv->descriptors[cmd.handle] = NULL;
+
+	return 0;
+}
+
+static int serial_poll_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	serial_poll_ioctl_t serial_cmd;
+	int retval;
+
+	GPIB_DPRINTK("pid %i, entering %s()\n", __func__, current->pid);
+
+	retval = copy_from_user(&serial_cmd, (void *)arg, sizeof(serial_cmd));
+	if (retval)
+		return -EFAULT;
+
+	retval = get_serial_poll_byte(board, serial_cmd.pad, serial_cmd.sad, board->usec_timeout,
+				      &serial_cmd.status_byte);
+	if (retval < 0)
+		return retval;
+
+	retval = copy_to_user((void *)arg, &serial_cmd, sizeof(serial_cmd));
+	if (retval)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int wait_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board,
+		      unsigned long arg)
+{
+	wait_ioctl_t wait_cmd;
+	int retval;
+	gpib_descriptor_t *desc;
+
+	retval = copy_from_user(&wait_cmd, (void *)arg, sizeof(wait_cmd));
+	if (retval)
+		return -EFAULT;
+
+	desc = handle_to_descriptor(file_priv, wait_cmd.handle);
+	if (!desc)
+		return -EINVAL;
+
+	retval = ibwait(board, wait_cmd.wait_mask, wait_cmd.clear_mask,
+			wait_cmd.set_mask, &wait_cmd.ibsta, wait_cmd.usec_timeout, desc);
+	if (retval < 0)
+		return retval;
+
+	retval = copy_to_user((void *)arg, &wait_cmd, sizeof(wait_cmd));
+	if (retval)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int parallel_poll_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	u8 poll_byte;
+	int retval;
+
+	retval = ibrpp(board, &poll_byte);
+	if (retval < 0)
+		return retval;
+
+	retval = copy_to_user((void *)arg, &poll_byte, sizeof(poll_byte));
+	if (retval)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int online_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	online_ioctl_t online_cmd;
+	int retval;
+	void *init_data = NULL;
+
+	board->config.init_data = NULL;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	retval = copy_from_user(&online_cmd, (void *)arg, sizeof(online_cmd));
+	if (retval)
+		return -EFAULT;
+	if (online_cmd.init_data_length > 0) {
+		board->config.init_data = vmalloc(online_cmd.init_data_length);
+		if (!board->config.init_data)
+			return -ENOMEM;
+		if (WARN_ON_ONCE(sizeof(init_data) > sizeof(online_cmd.init_data_ptr)))
+			return -EFAULT;
+		init_data = (void *)(unsigned long)(online_cmd.init_data_ptr);
+		retval = copy_from_user(board->config.init_data, init_data,
+					online_cmd.init_data_length);
+		if (retval) {
+			vfree(board->config.init_data);
+			return -EFAULT;
+		}
+		board->config.init_data_length = online_cmd.init_data_length;
+	} else {
+		board->config.init_data = NULL;
+		board->config.init_data_length = 0;
+	}
+	if (online_cmd.online)
+		retval = ibonline(board);
+	else
+		retval = iboffline(board);
+	if (board->config.init_data) {
+		vfree(board->config.init_data);
+		board->config.init_data = NULL;
+		board->config.init_data_length = 0;
+	}
+	return retval;
+}
+
+static int remote_enable_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	int enable;
+	int retval;
+
+	retval = copy_from_user(&enable, (void *)arg, sizeof(enable));
+	if (retval)
+		return -EFAULT;
+
+	return ibsre(board, enable);
+}
+
+static int take_control_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	int synchronous;
+	int retval;
+
+	retval = copy_from_user(&synchronous, (void *)arg, sizeof(synchronous));
+	if (retval)
+		return -EFAULT;
+
+	return ibcac(board, synchronous, 1);
+}
+
+static int line_status_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	short lines;
+	int retval;
+
+	retval = iblines(board, &lines);
+	if (retval < 0)
+		return retval;
+
+	retval = copy_to_user((void *)arg, &lines, sizeof(lines));
+	if (retval)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int pad_ioctl(gpib_board_t *board, gpib_file_private_t *file_priv,
+		     unsigned long arg)
+{
+	pad_ioctl_t cmd;
+	int retval;
+	gpib_descriptor_t *desc;
+
+	retval = copy_from_user(&cmd, (void *)arg, sizeof(cmd));
+	if (retval)
+		return -EFAULT;
+
+	desc = handle_to_descriptor(file_priv, cmd.handle);
+	if (!desc)
+		return -EINVAL;
+
+	if (desc->is_board) {
+		retval = ibpad(board, cmd.pad);
+		if (retval < 0)
+			return retval;
+	} else {
+		retval = decrement_open_device_count(&board->device_list, desc->pad, desc->sad);
+		if (retval < 0)
+			return retval;
+
+		desc->pad = cmd.pad;
+
+		retval = increment_open_device_count(&board->device_list, desc->pad, desc->sad);
+		if (retval < 0)
+			return retval;
+	}
+
+	return 0;
+}
+
+static int sad_ioctl(gpib_board_t *board, gpib_file_private_t *file_priv,
+		     unsigned long arg)
+{
+	sad_ioctl_t cmd;
+	int retval;
+	gpib_descriptor_t *desc;
+
+	retval = copy_from_user(&cmd, (void *)arg, sizeof(cmd));
+	if (retval)
+		return -EFAULT;
+
+	desc = handle_to_descriptor(file_priv, cmd.handle);
+	if (!desc)
+		return -EINVAL;
+
+	if (desc->is_board) {
+		retval = ibsad(board, cmd.sad);
+		if (retval < 0)
+			return retval;
+	} else {
+		retval = decrement_open_device_count(&board->device_list, desc->pad, desc->sad);
+		if (retval < 0)
+			return retval;
+
+		desc->sad = cmd.sad;
+
+		retval = increment_open_device_count(&board->device_list, desc->pad, desc->sad);
+		if (retval < 0)
+			return retval;
+	}
+	return 0;
+}
+
+static int eos_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	eos_ioctl_t eos_cmd;
+	int retval;
+
+	retval = copy_from_user(&eos_cmd, (void *)arg, sizeof(eos_cmd));
+	if (retval)
+		return -EFAULT;
+
+	return ibeos(board, eos_cmd.eos, eos_cmd.eos_flags);
+}
+
+static int request_service_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	u8 status_byte;
+	int retval;
+
+	retval = copy_from_user(&status_byte, (void *)arg, sizeof(status_byte));
+	if (retval)
+		return -EFAULT;
+
+	return ibrsv2(board, status_byte, status_byte & request_service_bit);
+}
+
+static int request_service2_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	request_service2_t request_service2_cmd;
+	int retval;
+
+	retval = copy_from_user(&request_service2_cmd, (void *)arg, sizeof(request_service2_t));
+	if (retval)
+		return -EFAULT;
+
+	return ibrsv2(board, request_service2_cmd.status_byte,
+		      request_service2_cmd.new_reason_for_service);
+}
+
+static int iobase_ioctl(gpib_board_config_t *config, unsigned long arg)
+{
+	u64 base_addr;
+	int retval;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	retval = copy_from_user(&base_addr, (void *)arg, sizeof(base_addr));
+	if (retval)
+		return -EFAULT;
+
+	if (WARN_ON_ONCE(sizeof(void *) > sizeof(base_addr)))
+		return -EFAULT;
+	config->ibbase = (void *)(unsigned long)(base_addr);
+
+	return 0;
+}
+
+static int irq_ioctl(gpib_board_config_t *config, unsigned long arg)
+{
+	unsigned int irq;
+	int retval;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	retval = copy_from_user(&irq, (void *)arg, sizeof(irq));
+	if (retval)
+		return -EFAULT;
+
+	config->ibirq = irq;
+
+	return 0;
+}
+
+static int dma_ioctl(gpib_board_config_t *config, unsigned long arg)
+{
+	unsigned int dma_channel;
+	int retval;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	retval = copy_from_user(&dma_channel, (void *)arg, sizeof(dma_channel));
+	if (retval)
+		return -EFAULT;
+
+	config->ibdma = dma_channel;
+
+	return 0;
+}
+
+static int autospoll_ioctl(gpib_board_t *board, gpib_file_private_t *file_priv,
+			   unsigned long arg)
+{
+	autospoll_ioctl_t enable;
+	int retval;
+	gpib_descriptor_t *desc;
+
+	retval = copy_from_user(&enable, (void *)arg, sizeof(enable));
+	if (retval)
+		return -EFAULT;
+
+	desc = handle_to_descriptor(file_priv, 0); /* board handle is 0 */
+
+	if (enable) {
+		if (!desc->autopoll_enabled) {
+			board->autospollers++;
+			desc->autopoll_enabled = 1;
+		}
+		retval = 0;
+	} else {
+		if (desc->autopoll_enabled) {
+			desc->autopoll_enabled = 0;
+			if (board->autospollers > 0) {
+				board->autospollers--;
+				retval = 0;
+			} else {
+				pr_err("gpib: tried to set number of autospollers negative\n");
+				retval = -EINVAL;
+			}
+		} else {
+			pr_err("gpib: autopoll disable requested before enable\n");
+			retval = -EINVAL;
+		}
+	}
+	return retval;
+}
+
+static int mutex_ioctl(gpib_board_t *board, gpib_file_private_t *file_priv,
+		       unsigned long arg)
+{
+	int retval, lock_mutex;
+
+	retval = copy_from_user(&lock_mutex, (void *)arg, sizeof(lock_mutex));
+	if (retval)
+		return -EFAULT;
+
+	if (lock_mutex)	{
+		retval = mutex_lock_interruptible(&board->user_mutex);
+		if (retval) {
+			pr_warn("gpib: ioctl interrupted while waiting on lock\n");
+			return -ERESTARTSYS;
+		}
+
+		spin_lock(&board->locking_pid_spinlock);
+		board->locking_pid = current->pid;
+		spin_unlock(&board->locking_pid_spinlock);
+
+		atomic_set(&file_priv->holding_mutex, 1);
+
+		GPIB_DPRINTK("pid %i, locked board %d mutex\n", current->pid, board->minor);
+	} else {
+		spin_lock(&board->locking_pid_spinlock);
+		if (current->pid != board->locking_pid) {
+			pr_err("gpib: bug! pid %i tried to release mutex held by pid %i\n",
+			       current->pid, board->locking_pid);
+			spin_unlock(&board->locking_pid_spinlock);
+			return -EPERM;
+		}
+		board->locking_pid = 0;
+		spin_unlock(&board->locking_pid_spinlock);
+
+		atomic_set(&file_priv->holding_mutex, 0);
+
+		mutex_unlock(&board->user_mutex);
+		GPIB_DPRINTK("pid %i, unlocked board %i mutex\n", current->pid, board->minor);
+	}
+	return 0;
+}
+
+static int timeout_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	unsigned int timeout;
+	int retval;
+
+	retval = copy_from_user(&timeout, (void *)arg, sizeof(timeout));
+	if (retval)
+		return -EFAULT;
+
+	board->usec_timeout = timeout;
+	GPIB_DPRINTK("pid %i, timeout set to %i usec\n", current->pid, timeout);
+
+	return 0;
+}
+
+static int ppc_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	ppoll_config_ioctl_t cmd;
+	int retval;
+
+	retval = copy_from_user(&cmd, (void *)arg, sizeof(cmd));
+	if (retval)
+		return -EFAULT;
+
+	if (cmd.set_ist) {
+		board->ist = 1;
+		board->interface->parallel_poll_response(board, board->ist);
+	} else if (cmd.clear_ist) {
+		board->ist = 0;
+		board->interface->parallel_poll_response(board, board->ist);
+	}
+
+	if (cmd.config)	{
+		retval = ibppc(board, cmd.config);
+		if (retval < 0)
+			return retval;
+	}
+
+	return 0;
+}
+
+static int set_local_ppoll_mode_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	local_ppoll_mode_ioctl_t cmd;
+	int retval;
+
+	retval = copy_from_user(&cmd, (void *)arg, sizeof(cmd));
+	if (retval)
+		return -EFAULT;
+
+	if (!board->interface->local_parallel_poll_mode)	{
+		pr_warn("gpib: local/remote parallel poll mode not supported by driver.");
+		return -EIO;
+	}
+	board->local_ppoll_mode = cmd != 0;
+	board->interface->local_parallel_poll_mode(board, board->local_ppoll_mode);
+
+	return 0;
+}
+
+static int get_local_ppoll_mode_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	local_ppoll_mode_ioctl_t cmd;
+	int retval;
+
+	cmd = board->local_ppoll_mode;
+	retval = copy_to_user((void *)arg, &cmd, sizeof(cmd));
+	if (retval)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int query_board_rsv_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	int status;
+	int retval;
+
+	status = board->interface->serial_poll_status(board);
+
+	retval = copy_to_user((void *)arg, &status, sizeof(status));
+	if (retval)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int board_info_ioctl(const gpib_board_t *board, unsigned long arg)
+{
+	board_info_ioctl_t info;
+	int retval;
+
+	info.pad = board->pad;
+	info.sad = board->sad;
+	info.parallel_poll_configuration = board->parallel_poll_configuration;
+	info.is_system_controller = board->master;
+	if (board->autospollers)
+		info.autopolling = 1;
+	else
+		info.autopolling = 0;
+	info.t1_delay = board->t1_nano_sec;
+	info.ist = board->ist;
+	info.no_7_bit_eos = board->interface->no_7_bit_eos;
+	retval = copy_to_user((void *)arg, &info, sizeof(info));
+	if (retval)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int interface_clear_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	unsigned int usec_duration;
+	int retval;
+
+	retval = copy_from_user(&usec_duration, (void *)arg, sizeof(usec_duration));
+	if (retval)
+		return -EFAULT;
+
+	return ibsic(board, usec_duration);
+}
+
+static int select_pci_ioctl(gpib_board_config_t *config, unsigned long arg)
+{
+	select_pci_ioctl_t selection;
+	int retval;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	retval = copy_from_user(&selection, (void *)arg, sizeof(selection));
+	if (retval)
+		return -EFAULT;
+
+	config->pci_bus = selection.pci_bus;
+	config->pci_slot = selection.pci_slot;
+
+	return 0;
+}
+
+static int select_device_path_ioctl(gpib_board_config_t *config, unsigned long arg)
+{
+	select_device_path_ioctl_t *selection;
+	int retval;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	selection = vmalloc(sizeof(select_device_path_ioctl_t));
+	if (!selection)
+		return -ENOMEM;
+
+	retval = copy_from_user(selection, (void *)arg, sizeof(select_device_path_ioctl_t));
+	if (retval) {
+		vfree(selection);
+		return -EFAULT;
+	}
+
+	selection->device_path[sizeof(selection->device_path) - 1] = '\0';
+	kfree(config->device_path);
+	config->device_path = NULL;
+	if (strlen(selection->device_path) > 0)
+		config->device_path = kstrdup(selection->device_path, GFP_KERNEL);
+
+	vfree(selection);
+	return 0;
+}
+
+unsigned int num_gpib_events(const gpib_event_queue_t *queue)
+{
+	return queue->num_events;
+}
+
+static int push_gpib_event_nolock(gpib_board_t *board, short event_type)
+{
+	gpib_event_queue_t *queue = &board->event_queue;
+	struct list_head *head = &queue->event_head;
+	gpib_event_t *event;
+	static const unsigned int max_num_events = 1024;
+	int retval;
+
+	if (num_gpib_events(queue) >= max_num_events) {
+		short lost_event;
+
+		queue->dropped_event = 1;
+		retval = pop_gpib_event_nolock(queue, &lost_event);
+		if (retval < 0)
+			return retval;
+	}
+
+	event = kmalloc(sizeof(gpib_event_t), GFP_ATOMIC);
+	if (!event) {
+		queue->dropped_event = 1;
+		pr_err("gpib: failed to allocate memory for event\n");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&event->list);
+	event->event_type = event_type;
+
+	list_add_tail(&event->list, head);
+
+	queue->num_events++;
+
+	GPIB_DPRINTK("pushed event %i, %i in queue\n",
+		     (int)event_type, num_gpib_events(queue));
+
+	return 0;
+}
+
+// push event onto back of event queue
+int push_gpib_event(gpib_board_t *board, short event_type)
+{
+	unsigned long flags;
+	int retval;
+
+	spin_lock_irqsave(&board->event_queue.lock, flags);
+	retval = push_gpib_event_nolock(board, event_type);
+	spin_unlock_irqrestore(&board->event_queue.lock, flags);
+
+	if (event_type == EventDevTrg)
+		board->status |= DTAS;
+	if (event_type == EventDevClr)
+		board->status |= DCAS;
+
+	return retval;
+}
+EXPORT_SYMBOL(push_gpib_event);
+
+static int pop_gpib_event_nolock(gpib_event_queue_t *queue, short *event_type)
+{
+	struct list_head *head = &queue->event_head;
+	struct list_head *front = head->next;
+	gpib_event_t *event;
+
+	if (num_gpib_events(queue) == 0) {
+		*event_type = EventNone;
+		return 0;
+	}
+
+	if (front == head)
+		return -EIO;
+
+	if (queue->dropped_event) {
+		queue->dropped_event = 0;
+		return -EPIPE;
+	}
+
+	event = list_entry(front, gpib_event_t, list);
+	*event_type = event->event_type;
+
+	list_del(front);
+	kfree(event);
+
+	queue->num_events--;
+
+	GPIB_DPRINTK("popped event %i, %i in queue\n",
+		     (int)*event_type, num_gpib_events(queue));
+
+	return 0;
+}
+
+// pop event from front of event queue
+int pop_gpib_event(gpib_event_queue_t *queue, short *event_type)
+{
+	unsigned long flags;
+	int retval;
+
+	spin_lock_irqsave(&queue->lock, flags);
+	retval = pop_gpib_event_nolock(queue, event_type);
+	spin_unlock_irqrestore(&queue->lock, flags);
+	return retval;
+}
+
+static int event_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	event_ioctl_t user_event;
+	int retval;
+	short event;
+
+	retval = pop_gpib_event(&board->event_queue, &event);
+	if (retval < 0)
+		return retval;
+
+	user_event = event;
+
+	retval = copy_to_user((void *)arg, &user_event, sizeof(user_event));
+	if (retval)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int request_system_control_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	rsc_ioctl_t request_control;
+	int retval;
+
+	retval = copy_from_user(&request_control, (void *)arg, sizeof(request_control));
+	if (retval)
+		return -EFAULT;
+
+	ibrsc(board, request_control);
+
+	return 0;
+}
+
+static int t1_delay_ioctl(gpib_board_t *board, unsigned long arg)
+{
+	t1_delay_ioctl_t cmd;
+	unsigned int delay;
+	int retval;
+
+	if (!board->interface->t1_delay)	{
+		pr_warn("gpib: t1 delay not implemented in driver!\n");
+		return -EIO;
+	}
+
+	retval = copy_from_user(&cmd, (void *)arg, sizeof(cmd));
+	if (retval)
+		return -EFAULT;
+
+	delay = cmd;
+
+	board->t1_nano_sec = board->interface->t1_delay(board, delay);
+
+	return 0;
+}
+
+const struct file_operations ib_fops = {
+owner: THIS_MODULE,
+llseek : NULL,
+unlocked_ioctl : &ibioctl,
+compat_ioctl : &ibioctl,
+open : &ibopen,
+release : &ibclose,
+};
+
+gpib_board_t board_array[GPIB_MAX_NUM_BOARDS];
+
+LIST_HEAD(registered_drivers);
+
+void init_gpib_descriptor(gpib_descriptor_t *desc)
+{
+	desc->pad = 0;
+	desc->sad = -1;
+	desc->is_board = 0;
+	desc->autopoll_enabled = 0;
+	atomic_set(&desc->io_in_progress, 0);
+}
+
+void gpib_register_driver(gpib_interface_t *interface, struct module *provider_module)
+{
+	struct gpib_interface_list_struct *entry;
+
+	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry) {
+		pr_err("gpib: failed register %s interface, out of memory\n", interface->name);
+		return;
+	}
+	entry->interface = interface;
+	entry->module = provider_module;
+	list_add(&entry->list, &registered_drivers);
+	pr_info("gpib: registered %s interface\n", interface->name);
+}
+EXPORT_SYMBOL(gpib_register_driver);
+
+void gpib_unregister_driver(gpib_interface_t *interface)
+{
+	int i;
+	struct list_head *list_ptr;
+
+	for (i = 0; i < GPIB_MAX_NUM_BOARDS; i++) {
+		gpib_board_t *board = &board_array[i];
+
+		if (board->interface == interface) {
+			if (board->use_count > 0)
+				pr_warn("gpib: Warning: deregistered interface %s in use\n",
+					interface->name);
+			iboffline(board);
+			board->interface = NULL;
+		}
+	}
+	for (list_ptr = registered_drivers.next; list_ptr != &registered_drivers;) {
+		gpib_interface_list_t *entry;
+
+		entry = list_entry(list_ptr, gpib_interface_list_t, list);
+		list_ptr = list_ptr->next;
+		if (entry->interface == interface) {
+			list_del(&entry->list);
+			kfree(entry);
+		}
+	}
+	pr_info("gpib: unregistered %s interface\n", interface->name);
+}
+EXPORT_SYMBOL(gpib_unregister_driver);
+
+static void init_gpib_board_config(gpib_board_config_t *config)
+{
+	memset(config, 0, sizeof(gpib_board_config_t));
+	config->pci_bus = -1;
+	config->pci_slot = -1;
+}
+
+void init_gpib_board(gpib_board_t *board)
+{
+	board->interface = NULL;
+	board->provider_module = NULL;
+	board->buffer = NULL;
+	board->buffer_length = 0;
+	board->status = 0;
+	init_waitqueue_head(&board->wait);
+	mutex_init(&board->user_mutex);
+	mutex_init(&board->big_gpib_mutex);
+	board->locking_pid = 0;
+	spin_lock_init(&board->locking_pid_spinlock);
+	spin_lock_init(&board->spinlock);
+	timer_setup(&board->timer, NULL, 0);
+	board->dev = NULL;
+	board->gpib_dev = NULL;
+	init_gpib_board_config(&board->config);
+	board->private_data = NULL;
+	board->use_count = 0;
+	INIT_LIST_HEAD(&board->device_list);
+	board->pad = 0;
+	board->sad = -1;
+	board->usec_timeout = 3000000;
+	board->parallel_poll_configuration = 0;
+	board->online = 0;
+	board->autospollers = 0;
+	board->autospoll_task = NULL;
+	init_event_queue(&board->event_queue);
+	board->minor = -1;
+	init_gpib_pseudo_irq(&board->pseudo_irq);
+	board->master = 1;
+	atomic_set(&board->stuck_srq, 0);
+	board->local_ppoll_mode = 0;
+}
+
+int gpib_allocate_board(gpib_board_t *board)
+{
+	if (!board->buffer) {
+		board->buffer_length = 0x4000;
+		board->buffer = vmalloc(board->buffer_length);
+		if (!board->buffer) {
+			board->buffer_length = 0;
+			return -ENOMEM;
+		}
+	}
+	return 0;
+}
+
+void gpib_deallocate_board(gpib_board_t *board)
+{
+	short dummy;
+
+	if (board->buffer) {
+		vfree(board->buffer);
+		board->buffer = NULL;
+		board->buffer_length = 0;
+	}
+	while (num_gpib_events(&board->event_queue))
+		pop_gpib_event(&board->event_queue, &dummy);
+}
+
+static void init_board_array(gpib_board_t *board_array, unsigned int length)
+{
+	int i;
+
+	for (i = 0; i < length; i++) {
+		init_gpib_board(&board_array[i]);
+		board_array[i].minor = i;
+	}
+}
+
+void init_gpib_status_queue(gpib_status_queue_t *device)
+{
+	INIT_LIST_HEAD(&device->list);
+	INIT_LIST_HEAD(&device->status_bytes);
+	device->num_status_bytes = 0;
+	device->reference_count = 0;
+	device->dropped_byte = 0;
+}
+
+static struct class *gpib_class;
+
+static int __init gpib_common_init_module(void)
+{
+	int i;
+
+	pr_info("Linux-GPIB core driver\n");
+	init_board_array(board_array, GPIB_MAX_NUM_BOARDS);
+	if (register_chrdev(GPIB_CODE, "gpib", &ib_fops)) {
+		pr_err("gpib: can't get major %d\n", GPIB_CODE);
+		return -EIO;
+	}
+	gpib_class = class_create("gpib_common");
+	if (IS_ERR(gpib_class)) {
+		pr_err("gpib: failed to create gpib class\n");
+		unregister_chrdev(GPIB_CODE, "gpib");
+		return PTR_ERR(gpib_class);
+	}
+	for (i = 0; i < GPIB_MAX_NUM_BOARDS; ++i)
+		board_array[i].gpib_dev = device_create(gpib_class, 0,
+							MKDEV(GPIB_CODE, i), NULL, "gpib%i", i);
+
+	return 0;
+}
+
+static void __exit gpib_common_exit_module(void)
+{
+	int i;
+
+	for (i = 0; i < GPIB_MAX_NUM_BOARDS; ++i)
+		device_destroy(gpib_class, MKDEV(GPIB_CODE, i));
+
+	class_destroy(gpib_class);
+	unregister_chrdev(GPIB_CODE, "gpib");
+}
+
+int gpib_match_device_path(struct device *dev, const char *device_path_in)
+{
+	if (device_path_in) {
+		char *device_path;
+
+		device_path = kobject_get_path(&dev->kobj, GFP_KERNEL);
+		if (!device_path) {
+			dev_err(dev, "kobject_get_path returned NULL.");
+			return 0;
+		}
+		if (strcmp(device_path_in, device_path) != 0) {
+			kfree(device_path);
+			return 0;
+		}
+		kfree(device_path);
+	}
+	return 1;
+}
+EXPORT_SYMBOL(gpib_match_device_path);
+
+struct pci_dev *gpib_pci_get_device(const gpib_board_config_t *config, unsigned int vendor_id,
+				    unsigned int device_id, struct pci_dev *from)
+{
+	struct pci_dev *pci_device = from;
+
+	while ((pci_device = pci_get_device(vendor_id, device_id, pci_device)))	{
+		if (config->pci_bus >= 0 && config->pci_bus != pci_device->bus->number)
+			continue;
+		if (config->pci_slot >= 0 && config->pci_slot !=
+		    PCI_SLOT(pci_device->devfn))
+			continue;
+		if (gpib_match_device_path(&pci_device->dev, config->device_path) == 0)
+			continue;
+		return pci_device;
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(gpib_pci_get_device);
+
+struct pci_dev *gpib_pci_get_subsys(const gpib_board_config_t *config, unsigned int vendor_id,
+				    unsigned int device_id, unsigned int ss_vendor,
+				    unsigned int ss_device,
+				    struct pci_dev *from)
+{
+	struct pci_dev *pci_device = from;
+
+	while ((pci_device = pci_get_subsys(vendor_id, device_id,
+					    ss_vendor, ss_device, pci_device))) {
+		if (config->pci_bus >= 0 && config->pci_bus != pci_device->bus->number)
+			continue;
+		if (config->pci_slot >= 0 && config->pci_slot !=
+		    PCI_SLOT(pci_device->devfn))
+			continue;
+		if (gpib_match_device_path(&pci_device->dev, config->device_path) == 0)
+			continue;
+		return pci_device;
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(gpib_pci_get_subsys);
+
+module_init(gpib_common_init_module);
+module_exit(gpib_common_exit_module);
+
diff --git a/drivers/staging/gpib/common/iblib.c b/drivers/staging/gpib/common/iblib.c
new file mode 100644
index 0000000000000000000000000000000000000000..83795e7f5cf14fcdfaa969186dc7dfbfacade40b
--- /dev/null
+++ b/drivers/staging/gpib/common/iblib.c
@@ -0,0 +1,740 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/***************************************************************************
+ *    copyright            : (C) 2001, 2002 by Frank Mori Hess
+ ***************************************************************************/
+
+#include "ibsys.h"
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/vmalloc.h>
+
+/*
+ * IBCAC
+ * Return to the controller active state from the
+ * controller standby state, i.e., turn ATN on.  Note
+ * that in order to enter the controller active state
+ * from the controller idle state, ibsic must be called.
+ * If sync is non-zero, attempt to take control synchronously.
+ * If fallback_to_async is non-zero, try to take control asynchronously
+ * if synchronous attempt fails.
+ */
+int ibcac(gpib_board_t *board, int sync, int fallback_to_async)
+{
+	int status = ibstatus(board);
+	int retval;
+
+	if ((status & CIC) == 0) {
+		pr_err("gpib: not CIC during %s()\n", __func__);
+		return -1;
+	}
+
+	if (status & ATN)
+		return 0;
+
+	if (sync && (status & LACS) == 0)
+		/* tcs (take control synchronously) can only possibly work when
+		 *  controller is listener.  Error code also needs to be -ETIMEDOUT
+		 *  or it will giveout without doing fallback.
+		 */
+		retval = -ETIMEDOUT;
+	else
+		retval = board->interface->take_control(board, sync);
+
+	if (retval < 0 && fallback_to_async) {
+		if (sync && retval == -ETIMEDOUT)
+			retval = board->interface->take_control(board, 0);
+	}
+	board->interface->update_status(board, 0);
+
+	return retval;
+}
+
+/* After ATN is asserted, it should cause any connected devices
+ * to start listening for command bytes and leave acceptor idle state.
+ * So if ATN is asserted and neither NDAC or NRFD are asserted,
+ * then there are no devices and ibcmd should error out immediately.
+ * Some gpib hardware sees itself asserting NDAC/NRFD when it
+ * is controller in charge, in which case this check will
+ * do nothing useful (but shouldn't cause any harm either).
+ * Drivers that don't need this check (ni_usb for example) may
+ * set the skip_check_for_command_acceptors flag in their
+ * gpib_interface_struct to avoid useless overhead.
+ */
+static int check_for_command_acceptors(gpib_board_t *board)
+{
+	int lines;
+
+	if (board->interface->skip_check_for_command_acceptors)
+		return 0;
+	if (!board->interface->line_status)
+		return 0;
+
+	udelay(2); // allow time for devices to respond to ATN if it was just asserted
+
+	lines = board->interface->line_status(board);
+	if (lines < 0)
+		return lines;
+
+	if (lines & ValidATN) {
+		if ((lines & BusATN) == 0) {
+			pr_err("gpib: ATN not asserted in %s()?", __func__);
+			return 0;
+		}
+	}
+
+	if ((lines & ValidNRFD) && (lines & ValidNDAC))	{
+		if ((lines & BusNRFD) == 0 && (lines & BusNDAC) == 0)
+			return -ENOTCONN;
+	}
+
+	return 0;
+}
+
+/*
+ * IBCMD
+ * Write cnt command bytes from buf to the GPIB.  The
+ * command operation terminates only on I/O complete.
+ *
+ * NOTE:
+ *      1.  Prior to beginning the command, the interface is
+ *          placed in the controller active state.
+ *      2.  Before calling ibcmd for the first time, ibsic
+ *          must be called to initialize the GPIB and enable
+ *          the interface to leave the controller idle state.
+ */
+int ibcmd(gpib_board_t *board, uint8_t *buf, size_t length, size_t *bytes_written)
+{
+	ssize_t ret = 0;
+	int status;
+
+	*bytes_written = 0;
+
+	status = ibstatus(board);
+
+	if ((status & CIC) == 0) {
+		pr_err("gpib: cannot send command when not controller-in-charge\n");
+		return -EIO;
+	}
+
+	os_start_timer(board, board->usec_timeout);
+
+	ret = ibcac(board, 1, 1);
+	if (ret == 0) {
+		ret = check_for_command_acceptors(board);
+		if (ret == 0)
+			ret = board->interface->command(board, buf, length, bytes_written);
+	}
+
+	os_remove_timer(board);
+
+	if (io_timed_out(board))
+		ret = -ETIMEDOUT;
+
+	return ret;
+}
+
+/*
+ * IBGTS
+ * Go to the controller standby state from the controller
+ * active state, i.e., turn ATN off.
+ */
+
+int ibgts(gpib_board_t *board)
+{
+	int status = ibstatus(board);
+	int retval;
+
+	if ((status & CIC) == 0) {
+		pr_err("gpib: not CIC during %s()\n", __func__);
+		return -1;
+	}
+
+	retval = board->interface->go_to_standby(board);    /* go to standby */
+	if (retval < 0)
+		pr_err("gpib: error while going to standby\n");
+
+	board->interface->update_status(board, 0);
+
+	return retval;
+}
+
+static int autospoll_wait_should_wake_up(gpib_board_t *board)
+{
+	int retval;
+
+	mutex_lock(&board->big_gpib_mutex);
+
+	retval = board->master && board->autospollers > 0 &&
+		!atomic_read(&board->stuck_srq) &&
+		test_and_clear_bit(SRQI_NUM, &board->status);
+
+	mutex_unlock(&board->big_gpib_mutex);
+	return retval;
+}
+
+static int autospoll_thread(void *board_void)
+{
+	gpib_board_t *board = board_void;
+	int retval = 0;
+
+	GPIB_DPRINTK("entering autospoll thread\n");
+
+	while (1) {
+		wait_event_interruptible(board->wait,
+					 kthread_should_stop() ||
+					 autospoll_wait_should_wake_up(board));
+		GPIB_DPRINTK("autospoll wait satisfied\n");
+		if (kthread_should_stop())
+			break;
+
+		mutex_lock(&board->big_gpib_mutex);
+		/* make sure we are still good after we have lock */
+		if (board->autospollers <= 0 || board->master == 0) {
+			mutex_unlock(&board->big_gpib_mutex);
+			continue;
+		}
+		mutex_unlock(&board->big_gpib_mutex);
+
+		if (try_module_get(board->provider_module)) {
+			retval = autopoll_all_devices(board);
+			module_put(board->provider_module);
+		} else {
+			pr_err("gpib%i: %s: try_module_get() failed!\n", board->minor, __func__);
+		}
+		if (retval <= 0) {
+			pr_err("gpib%i: %s: stuck SRQ\n", board->minor, __func__);
+
+			atomic_set(&board->stuck_srq, 1);	// XXX could be better
+			set_bit(SRQI_NUM, &board->status);
+		}
+	}
+	pr_info("gpib%i: exiting autospoll thread\n", board->minor);
+	return retval;
+}
+
+int ibonline(gpib_board_t *board)
+{
+	int retval;
+
+	if (board->online)
+		return -EBUSY;
+	if (!board->interface)
+		return -ENODEV;
+	retval = gpib_allocate_board(board);
+	if (retval < 0)
+		return retval;
+
+	board->dev = NULL;
+	board->local_ppoll_mode = 0;
+	retval = board->interface->attach(board, &board->config);
+	if (retval < 0) {
+		board->interface->detach(board);
+		pr_err("gpib: interface attach failed\n");
+		return retval;
+	}
+	/* nios2nommu on 2.6.11 uclinux kernel has weird problems
+	 * with autospoll thread causing huge slowdowns
+	 */
+#ifndef CONFIG_NIOS2
+	board->autospoll_task = kthread_run(&autospoll_thread, board,
+					    "gpib%d_autospoll_kthread", board->minor);
+	retval = IS_ERR(board->autospoll_task);
+	if (retval) {
+		pr_err("gpib: failed to create autospoll thread\n");
+		board->interface->detach(board);
+		return retval;
+	}
+#endif
+	board->online = 1;
+	GPIB_DPRINTK("gpib: board online\n");
+
+	return 0;
+}
+
+/* XXX need to make sure board is generally not in use (grab board lock?) */
+int iboffline(gpib_board_t *board)
+{
+	int retval;
+
+	if (board->online == 0)
+		return 0;
+	if (!board->interface)
+		return -ENODEV;
+
+	if (board->autospoll_task && !IS_ERR(board->autospoll_task)) {
+		retval = kthread_stop(board->autospoll_task);
+		if (retval)
+			pr_err("gpib: kthread_stop returned %i\n", retval);
+		board->autospoll_task = NULL;
+	}
+
+	board->interface->detach(board);
+	gpib_deallocate_board(board);
+	board->online = 0;
+	GPIB_DPRINTK("gpib: board offline\n");
+
+	return 0;
+}
+
+/*
+ * IBLINES
+ * Poll the GPIB control lines and return their status in buf.
+ *
+ *      LSB (bits 0-7)  -  VALID lines mask (lines that can be monitored).
+ * Next LSB (bits 8-15) - STATUS lines mask (lines that are currently set).
+ *
+ */
+int iblines(const gpib_board_t *board, short *lines)
+{
+	int retval;
+
+	*lines = 0;
+	if (!board->interface->line_status)
+		return 0;
+	retval = board->interface->line_status(board);
+	if (retval < 0)
+		return retval;
+	*lines = retval;
+	return 0;
+}
+
+/*
+ * IBRD
+ * Read up to 'length' bytes of data from the GPIB into buf.  End
+ * on detection of END (EOI and or EOS) and set 'end_flag'.
+ *
+ * NOTE:
+ *      1.  The interface is placed in the controller standby
+ *          state prior to beginning the read.
+ *      2.  Prior to calling ibrd, the intended devices as well
+ *          as the interface board itself must be addressed by
+ *          calling ibcmd.
+ */
+
+int ibrd(gpib_board_t *board, uint8_t *buf, size_t length, int *end_flag, size_t *nbytes)
+{
+	ssize_t ret = 0;
+	int retval;
+	size_t bytes_read;
+
+	*nbytes = 0;
+	*end_flag = 0;
+	if (length == 0) {
+		pr_warn("gpib: %s() called with zero length?\n",  __func__);
+		return 0;
+	}
+
+	if (board->master) {
+		retval = ibgts(board);
+		if (retval < 0)
+			return retval;
+	}
+	/* XXX resetting timer here could cause timeouts take longer than they should,
+	 * since read_ioctl calls this
+	 * function in a loop, there is probably a similar problem with writes/commands
+	 */
+	os_start_timer(board, board->usec_timeout);
+
+	do {
+		ret = board->interface->read(board, buf, length - *nbytes, end_flag, &bytes_read);
+		if (ret < 0) {
+			pr_err("gpib read error\n");
+			goto ibrd_out;
+		}
+		buf += bytes_read;
+		*nbytes += bytes_read;
+		if (need_resched())
+			schedule();
+	} while (ret == 0 && *nbytes > 0 && *nbytes < length && *end_flag == 0);
+ibrd_out:
+	os_remove_timer(board);
+
+	return ret;
+}
+
+/*
+ * IBRPP
+ * Conduct a parallel poll and return the byte in buf.
+ *
+ * NOTE:
+ *	1.  Prior to conducting the poll the interface is placed
+ *	    in the controller active state.
+ */
+int ibrpp(gpib_board_t *board, uint8_t *result)
+{
+	int retval = 0;
+
+	os_start_timer(board, board->usec_timeout);
+	retval = ibcac(board, 1, 1);
+	if (retval)
+		return -1;
+
+	if (board->interface->parallel_poll(board, result)) {
+		pr_err("gpib: parallel poll failed\n");
+		retval = -1;
+	}
+	os_remove_timer(board);
+	return retval;
+}
+
+int ibppc(gpib_board_t *board, uint8_t configuration)
+{
+	configuration &= 0x1f;
+	board->interface->parallel_poll_configure(board, configuration);
+	board->parallel_poll_configuration = configuration;
+
+	return 0;
+}
+
+int ibrsv2(gpib_board_t *board, uint8_t status_byte, int new_reason_for_service)
+{
+	int board_status = ibstatus(board);
+	const unsigned int MSS = status_byte & request_service_bit;
+
+	if ((board_status & CIC)) {
+		pr_err("gpib: interface requested service while CIC\n");
+		return -EINVAL;
+	}
+
+	if (MSS == 0 && new_reason_for_service)
+		return -EINVAL;
+
+	if (board->interface->serial_poll_response2)	{
+		board->interface->serial_poll_response2(board, status_byte, new_reason_for_service);
+		// fall back on simpler serial_poll_response if the behavior would be the same
+	} else if (board->interface->serial_poll_response &&
+		   (MSS == 0 || (MSS && new_reason_for_service))) {
+		board->interface->serial_poll_response(board, status_byte);
+	} else {
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+/*
+ * IBSIC
+ * Send IFC for at least 100 microseconds.
+ *
+ * NOTE:
+ *	1.  Ibsic must be called prior to the first call to
+ *	    ibcmd in order to initialize the bus and enable the
+ *	    interface to leave the controller idle state.
+ */
+int ibsic(gpib_board_t *board, unsigned int usec_duration)
+{
+	if (board->master == 0)	{
+		pr_err("gpib: tried to assert IFC when not system controller\n");
+		return -1;
+	}
+
+	if (usec_duration < 100)
+		usec_duration = 100;
+	if (usec_duration > 1000) {
+		usec_duration = 1000;
+		pr_warn("gpib: warning, shortening long udelay\n");
+	}
+
+	GPIB_DPRINTK("sending interface clear\n");
+	board->interface->interface_clear(board, 1);
+	udelay(usec_duration);
+	board->interface->interface_clear(board, 0);
+
+	return 0;
+}
+
+void ibrsc(gpib_board_t *board, int request_control)
+{
+	board->master = request_control != 0;
+	if (!board->interface->request_system_control)	{
+		pr_err("gpib: bug! driver does not implement request_system_control()\n");
+		return;
+	}
+	board->interface->request_system_control(board, request_control);
+}
+
+/*
+ * IBSRE
+ * Send REN true if v is non-zero or false if v is zero.
+ */
+int ibsre(gpib_board_t *board, int enable)
+{
+	if (board->master == 0)	{
+		pr_err("gpib: tried to set REN when not system controller\n");
+		return -1;
+	}
+
+	board->interface->remote_enable(board, enable);	/* set or clear REN */
+	if (!enable)
+		usleep_range(100, 150);
+
+	return 0;
+}
+
+/*
+ * IBPAD
+ * change the GPIB address of the interface board.  The address
+ * must be 0 through 30.  ibonl resets the address to PAD.
+ */
+int ibpad(gpib_board_t *board, unsigned int addr)
+{
+	if (addr > 30) {
+		pr_err("gpib: invalid primary address %u\n", addr);
+		return -1;
+	}
+	board->pad = addr;
+	if (board->online)
+		board->interface->primary_address(board, board->pad);
+	GPIB_DPRINTK("set primary addr to %i\n", board->pad);
+	return 0;
+}
+
+/*
+ * IBSAD
+ * change the secondary GPIB address of the interface board.
+ * The address must be 0 through 30, or negative disables.  ibonl resets the
+ * address to SAD.
+ */
+int ibsad(gpib_board_t *board, int addr)
+{
+	if (addr > 30) {
+		pr_err("gpib: invalid secondary address %i, must be 0-30\n", addr);
+		return -1;
+	}
+	board->sad = addr;
+	if (board->online) {
+		if (board->sad >= 0)
+			board->interface->secondary_address(board, board->sad, 1);
+		else
+			board->interface->secondary_address(board, 0, 0);
+	}
+	GPIB_DPRINTK("set secondary addr to %i\n", board->sad);
+
+	return 0;
+}
+
+/*
+ * IBEOS
+ * Set the end-of-string modes for I/O operations to v.
+ *
+ */
+int ibeos(gpib_board_t *board, int eos, int eosflags)
+{
+	int retval;
+
+	if (eosflags & ~EOS_MASK) {
+		pr_err("bad EOS modes\n");
+		return -EINVAL;
+	}
+	if (eosflags & REOS) {
+		retval = board->interface->enable_eos(board, eos, eosflags & BIN);
+	} else {
+		board->interface->disable_eos(board);
+		retval = 0;
+	}
+	return retval;
+}
+
+int ibstatus(gpib_board_t *board)
+{
+	return general_ibstatus(board, NULL, 0, 0, NULL);
+}
+
+int general_ibstatus(gpib_board_t *board, const gpib_status_queue_t *device,
+		     int clear_mask, int set_mask, gpib_descriptor_t *desc)
+{
+	int status = 0;
+	short line_status;
+
+	if (board->private_data) {
+		status = board->interface->update_status(board, clear_mask);
+		/* XXX should probably stop having drivers use TIMO bit in
+		 * board->status to avoid confusion
+		 */
+		status &= ~TIMO;
+		/* get real SRQI status if we can */
+		if (iblines(board, &line_status) == 0) {
+			if ((line_status & ValidSRQ)) {
+				if ((line_status & BusSRQ))
+					status |= SRQI;
+				else
+					status &= ~SRQI;
+			}
+		}
+	}
+	if (device)
+		if (num_status_bytes(device))
+			status |= RQS;
+
+	if (desc) {
+		if (set_mask & CMPL)
+			atomic_set(&desc->io_in_progress, 0);
+		else if (clear_mask & CMPL)
+			atomic_set(&desc->io_in_progress, 1);
+
+		if (atomic_read(&desc->io_in_progress))
+			status &= ~CMPL;
+		else
+			status |= CMPL;
+	}
+	if (num_gpib_events(&board->event_queue))
+		status |= EVENT;
+	else
+		status &= ~EVENT;
+
+	return status;
+}
+
+struct wait_info {
+	gpib_board_t *board;
+	struct timer_list timer;
+	int timed_out;
+	unsigned long usec_timeout;
+};
+
+static void wait_timeout(struct timer_list *t)
+{
+	struct wait_info *winfo = from_timer(winfo, t, timer);
+
+	winfo->timed_out = 1;
+	wake_up_interruptible(&winfo->board->wait);
+}
+
+static void init_wait_info(struct wait_info *winfo)
+{
+	winfo->board = NULL;
+	winfo->timed_out = 0;
+	timer_setup_on_stack(&winfo->timer, wait_timeout, 0);
+}
+
+static int wait_satisfied(struct wait_info *winfo, gpib_status_queue_t *status_queue,
+			  int wait_mask, int *status, gpib_descriptor_t *desc)
+{
+	gpib_board_t *board = winfo->board;
+	int temp_status;
+
+	if (mutex_lock_interruptible(&board->big_gpib_mutex))
+		return -ERESTARTSYS;
+
+	temp_status = general_ibstatus(board, status_queue, 0, 0, desc);
+
+	mutex_unlock(&board->big_gpib_mutex);
+
+	if (winfo->timed_out)
+		temp_status |= TIMO;
+	else
+		temp_status &= ~TIMO;
+	if (wait_mask & temp_status) {
+		*status = temp_status;
+		return 1;
+	}
+//XXX does wait for END work?
+	return 0;
+}
+
+/* install timer interrupt handler */
+static void start_wait_timer(struct wait_info *winfo)
+/* Starts the timeout task  */
+{
+	winfo->timed_out = 0;
+
+	if (winfo->usec_timeout > 0)
+		mod_timer(&winfo->timer, jiffies + usec_to_jiffies(winfo->usec_timeout));
+}
+
+static void remove_wait_timer(struct wait_info *winfo)
+{
+	del_timer_sync(&winfo->timer);
+	destroy_timer_on_stack(&winfo->timer);
+}
+
+/*
+ * IBWAIT
+ * Check or wait for a GPIB event to occur.  The mask argument
+ * is a bit vector corresponding to the status bit vector.  It
+ * has a bit set for each condition which can terminate the wait
+ * If the mask is 0 then
+ * no condition is waited for.
+ */
+int ibwait(gpib_board_t *board, int wait_mask, int clear_mask, int set_mask,
+	   int *status, unsigned long usec_timeout, gpib_descriptor_t *desc)
+{
+	int retval = 0;
+	gpib_status_queue_t *status_queue;
+	struct wait_info winfo;
+
+	if (desc->is_board)
+		status_queue = NULL;
+	else
+		status_queue = get_gpib_status_queue(board, desc->pad, desc->sad);
+
+	if (wait_mask == 0) {
+		*status = general_ibstatus(board, status_queue, clear_mask, set_mask, desc);
+		return 0;
+	}
+
+	mutex_unlock(&board->big_gpib_mutex);
+
+	init_wait_info(&winfo);
+	winfo.board = board;
+	winfo.usec_timeout = usec_timeout;
+	start_wait_timer(&winfo);
+
+	if (wait_event_interruptible(board->wait, wait_satisfied(&winfo, status_queue,
+								 wait_mask, status, desc))) {
+		GPIB_DPRINTK("wait interrupted\n");
+		retval = -ERESTARTSYS;
+	}
+	remove_wait_timer(&winfo);
+
+	if (retval)
+		return retval;
+	if (mutex_lock_interruptible(&board->big_gpib_mutex))
+		return -ERESTARTSYS;
+
+	/* make sure we only clear status bits that we are reporting */
+	if (*status & clear_mask || set_mask)
+		general_ibstatus(board, status_queue, *status & clear_mask, set_mask, 0);
+
+	return 0;
+}
+
+/*
+ * IBWRT
+ * Write cnt bytes of data from buf to the GPIB.  The write
+ * operation terminates only on I/O complete.
+ *
+ * NOTE:
+ *      1.  Prior to beginning the write, the interface is
+ *          placed in the controller standby state.
+ *      2.  Prior to calling ibwrt, the intended devices as
+ *          well as the interface board itself must be
+ *          addressed by calling ibcmd.
+ */
+int ibwrt(gpib_board_t *board, uint8_t *buf, size_t cnt, int send_eoi, size_t *bytes_written)
+{
+	int ret = 0;
+	int retval;
+
+	if (cnt == 0) {
+		pr_warn("gpib: %s() called with zero length?\n", __func__);
+		return 0;
+	}
+
+	if (board->master) {
+		retval = ibgts(board);
+		if (retval < 0)
+			return retval;
+	}
+	os_start_timer(board, board->usec_timeout);
+	ret = board->interface->write(board, buf, cnt, send_eoi, bytes_written);
+
+	if (io_timed_out(board))
+		ret = -ETIMEDOUT;
+
+	os_remove_timer(board);
+
+	return ret;
+}
+
diff --git a/drivers/staging/gpib/common/ibsys.h b/drivers/staging/gpib/common/ibsys.h
new file mode 100644
index 0000000000000000000000000000000000000000..3f53a808a9b9c81581826faf80fee910f022c5c9
--- /dev/null
+++ b/drivers/staging/gpib/common/ibsys.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include "gpibP.h"
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+int gpib_allocate_board(gpib_board_t *board);
+void gpib_deallocate_board(gpib_board_t *board);
+
+unsigned int num_status_bytes(const gpib_status_queue_t *dev);
+int push_status_byte(gpib_status_queue_t *device, uint8_t poll_byte);
+int pop_status_byte(gpib_status_queue_t *device, uint8_t *poll_byte);
+gpib_status_queue_t *get_gpib_status_queue(gpib_board_t *board, unsigned int pad, int sad);
+int get_serial_poll_byte(gpib_board_t *board, unsigned int pad, int sad,
+			 unsigned int usec_timeout, uint8_t *poll_byte);
+int autopoll_all_devices(gpib_board_t *board);