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

Commit 00e8c494 authored by kogiidena's avatar kogiidena Committed by Paul Mundt
Browse files

sh: landisk updates.



Updates for the landisk board:

	- The push_switch framework was used.
	- landisk_pwb.c was divided into psw.c and gio.c.
	- pata_platform was supported in USL-5P.
	- irq.c was rewritten.
	- io.c was replaced with generic I/O routines.

Signed-off-by: default avatarkogiidena <kogiidena@eggplant.ddo.jp>
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent 5753171b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2,4 +2,4 @@
# Makefile for I-O DATA DEVICE, INC. "LANDISK Series"
#

obj-y	 := setup.o io.o irq.o rtc.o landisk_pwb.o
obj-y	 := setup.o irq.o psw.o gio.o
+167 −0
Original line number Diff line number Diff line
/*
 * arch/sh/boards/landisk/gio.c - driver for landisk
 *
 * This driver will also support the I-O DATA Device, Inc. LANDISK Board.
 * LANDISK and USL-5P Button, LED and GIO driver drive function.
 *
 *   Copylight (C) 2006 kogiidena
 *   Copylight (C) 2002 Atom Create Engineering Co., Ltd. *
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/landisk/gio.h>
#include <asm/landisk/iodata_landisk.h>

#define DEVCOUNT                4
#define GIO_MINOR	        2	/* GIO minor no. */

static dev_t dev;
static struct cdev *cdev_p;
static int openCnt;

static int gio_open(struct inode *inode, struct file *filp)
{
	int minor;

	minor = MINOR(inode->i_rdev);
	if (minor < DEVCOUNT) {
		if (openCnt > 0) {
			return -EALREADY;
		} else {
			openCnt++;
			return 0;
		}
	}
	return -ENOENT;
}

static int gio_close(struct inode *inode, struct file *filp)
{
	int minor;

	minor = MINOR(inode->i_rdev);
	if (minor < DEVCOUNT) {
		openCnt--;
	}
	return 0;
}

static int gio_ioctl(struct inode *inode, struct file *filp,
			     unsigned int cmd, unsigned long arg)
{
	unsigned int data;
	static unsigned int addr = 0;

	if (cmd & 0x01) {	/* write */
		if (copy_from_user(&data, (int *)arg, sizeof(int))) {
			return -EFAULT;
		}
	}

	switch (cmd) {
	case GIODRV_IOCSGIOSETADDR:	/* addres set */
		addr = data;
		break;

	case GIODRV_IOCSGIODATA1:	/* write byte */
		ctrl_outb((unsigned char)(0x0ff & data), addr);
		break;

	case GIODRV_IOCSGIODATA2:	/* write word */
		if (addr & 0x01) {
			return -EFAULT;
		}
		ctrl_outw((unsigned short int)(0x0ffff & data), addr);
		break;

	case GIODRV_IOCSGIODATA4:	/* write long */
		if (addr & 0x03) {
			return -EFAULT;
		}
		ctrl_outl(data, addr);
		break;

	case GIODRV_IOCGGIODATA1:	/* read byte */
		data = ctrl_inb(addr);
		break;

	case GIODRV_IOCGGIODATA2:	/* read word */
		if (addr & 0x01) {
			return -EFAULT;
		}
		data = ctrl_inw(addr);
		break;

	case GIODRV_IOCGGIODATA4:	/* read long */
		if (addr & 0x03) {
			return -EFAULT;
		}
		data = ctrl_inl(addr);
		break;
	default:
		return -EFAULT;
		break;
	}

	if ((cmd & 0x01) == 0) {	/* read */
		if (copy_to_user((int *)arg, &data, sizeof(int))) {
			return -EFAULT;
		}
	}
	return 0;
}

static struct file_operations gio_fops = {
	.owner = THIS_MODULE,
	.open = gio_open,	/* open */
	.release = gio_close,	/* release */
	.ioctl = gio_ioctl,	/* ioctl */
};

static int __init gio_init(void)
{
	int error;

	printk(KERN_INFO "gio: driver initialized\n");

	openCnt = 0;

	if ((error = alloc_chrdev_region(&dev, 0, DEVCOUNT, "gio")) < 0) {
		printk(KERN_ERR
		       "gio: Couldn't alloc_chrdev_region, error=%d\n",
		       error);
		return 1;
	}

	cdev_p = cdev_alloc();
	cdev_p->ops = &gio_fops;
	error = cdev_add(cdev_p, dev, DEVCOUNT);
	if (error) {
		printk(KERN_ERR
		       "gio: Couldn't cdev_add, error=%d\n", error);
		return 1;
	}

	return 0;
}

static void __exit gio_exit(void)
{
	cdev_del(cdev_p);
	unregister_chrdev_region(dev, DEVCOUNT);
}

module_init(gio_init);
module_exit(gio_exit);

MODULE_LICENSE("GPL");

arch/sh/boards/landisk/io.c

deleted100644 → 0
+0 −250
Original line number Diff line number Diff line
/*
 * arch/sh/boards/landisk/io.c
 *
 * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
 * Based largely on io_se.c.
 *
 * I/O routine for I-O Data Device, Inc. LANDISK.
 *
 * Initial version only to support LAN access; some
 * placeholder code from io_landisk.c left in with the
 * expectation of later SuperIO and PCMCIA access.
 */
/*
 * modifed by kogiidena
 * 2005.03.03
 */
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <asm/landisk/iodata_landisk.h>
#include <asm/addrspace.h>
#include <asm/io.h>

extern void *area5_io_base;	/* Area 5 I/O Base address */
extern void *area6_io_base;	/* Area 6 I/O Base address */

static inline unsigned long port2adr(unsigned int port)
{
	if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
		if (port == 0x3f6)
			return ((unsigned long)area5_io_base + 0x2c);
		else
			return ((unsigned long)area5_io_base + PA_PIDE_OFFSET +
				((port - 0x1f0) << 1));
	else if ((0x170 <= port && port < 0x178) || port == 0x376)
		if (port == 0x376)
			return ((unsigned long)area6_io_base + 0x2c);
		else
			return ((unsigned long)area6_io_base + PA_SIDE_OFFSET +
				((port - 0x170) << 1));
	else
		maybebadio((unsigned long)port);

	return port;
}

/*
 * General outline: remap really low stuff [eventually] to SuperIO,
 * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
 * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
 * should be way beyond the window, and is used  w/o translation for
 * compatibility.
 */
u8 landisk_inb(unsigned long port)
{
	if (PXSEG(port))
		return ctrl_inb(port);
	else if (is_pci_ioaddr(port))
		return ctrl_inb(pci_ioaddr(port));

	return ctrl_inw(port2adr(port)) & 0xff;
}

u8 landisk_inb_p(unsigned long port)
{
	u8 v;

	if (PXSEG(port))
		v = ctrl_inb(port);
	else if (is_pci_ioaddr(port))
		v = ctrl_inb(pci_ioaddr(port));
	else
		v = ctrl_inw(port2adr(port)) & 0xff;

	ctrl_delay();

	return v;
}

u16 landisk_inw(unsigned long port)
{
	if (PXSEG(port))
		return ctrl_inw(port);
	else if (is_pci_ioaddr(port))
		return ctrl_inw(pci_ioaddr(port));
	else
		maybebadio(port);

	return 0;
}

u32 landisk_inl(unsigned long port)
{
	if (PXSEG(port))
		return ctrl_inl(port);
	else if (is_pci_ioaddr(port))
		return ctrl_inl(pci_ioaddr(port));
	else
		maybebadio(port);

	return 0;
}

void landisk_outb(u8 value, unsigned long port)
{
	if (PXSEG(port))
		ctrl_outb(value, port);
	else if (is_pci_ioaddr(port))
		ctrl_outb(value, pci_ioaddr(port));
	else
		ctrl_outw(value, port2adr(port));
}

void landisk_outb_p(u8 value, unsigned long port)
{
	if (PXSEG(port))
		ctrl_outb(value, port);
	else if (is_pci_ioaddr(port))
		ctrl_outb(value, pci_ioaddr(port));
	else
		ctrl_outw(value, port2adr(port));
	ctrl_delay();
}

void landisk_outw(u16 value, unsigned long port)
{
	if (PXSEG(port))
		ctrl_outw(value, port);
	else if (is_pci_ioaddr(port))
		ctrl_outw(value, pci_ioaddr(port));
	else
		maybebadio(port);
}

void landisk_outl(u32 value, unsigned long port)
{
	if (PXSEG(port))
		ctrl_outl(value, port);
	else if (is_pci_ioaddr(port))
		ctrl_outl(value, pci_ioaddr(port));
	else
		maybebadio(port);
}

void landisk_insb(unsigned long port, void *dst, unsigned long count)
{
        volatile u16 *p;
        u8 *buf = dst;

        if (PXSEG(port)) {
                while (count--)
                        *buf++ = *(volatile u8 *)port;
	} else if (is_pci_ioaddr(port)) {
                volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);

                while (count--)
                        *buf++ = *bp;
	} else {
                p = (volatile u16 *)port2adr(port);
                while (count--)
                        *buf++ = *p & 0xff;
	}
}

void landisk_insw(unsigned long port, void *dst, unsigned long count)
{
        volatile u16 *p;
        u16 *buf = dst;

	if (PXSEG(port))
		p = (volatile u16 *)port;
	else if (is_pci_ioaddr(port))
		p = (volatile u16 *)pci_ioaddr(port);
	else
		p = (volatile u16 *)port2adr(port);
	while (count--)
		*buf++ = *p;
}

void landisk_insl(unsigned long port, void *dst, unsigned long count)
{
        u32 *buf = dst;

	if (is_pci_ioaddr(port)) {
                volatile u32 *p = (volatile u32 *)pci_ioaddr(port);

                while (count--)
                        *buf++ = *p;
	} else
		maybebadio(port);
}

void landisk_outsb(unsigned long port, const void *src, unsigned long count)
{
        volatile u16 *p;
        const u8 *buf = src;

	if (PXSEG(port))
                while (count--)
                        ctrl_outb(*buf++, port);
	else if (is_pci_ioaddr(port)) {
                volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);

                while (count--)
                        *bp = *buf++;
	} else {
                p = (volatile u16 *)port2adr(port);
                while (count--)
                        *p = *buf++;
	}
}

void landisk_outsw(unsigned long port, const void *src, unsigned long count)
{
        volatile u16 *p;
        const u16 *buf = src;

	if (PXSEG(port))
                p = (volatile u16 *)port;
	else if (is_pci_ioaddr(port))
                p = (volatile u16 *)pci_ioaddr(port);
	else
                p = (volatile u16 *)port2adr(port);

        while (count--)
                *p = *buf++;
}

void landisk_outsl(unsigned long port, const void *src, unsigned long count)
{
        const u32 *buf = src;

	if (is_pci_ioaddr(port)) {
                volatile u32 *p = (volatile u32 *)pci_ioaddr(port);

                while (count--)
                        *p = *buf++;
	} else
		maybebadio(port);
}

void __iomem *landisk_ioport_map(unsigned long port, unsigned int size)
{
        if (PXSEG(port))
                return (void __iomem *)port;
        else if (is_pci_ioaddr(port))
                return (void __iomem *)pci_ioaddr(port);

        return (void __iomem *)port2adr(port);
}
+21 −62
Original line number Diff line number Diff line
/*
 * arch/sh/boards/landisk/irq.c
 *
 * I-O DATA Device, Inc. LANDISK Support
 *
 * Copyright (C) 2005-2007 kogiidena
 *
 * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
 * Based largely on io_se.c.
 *
 * I/O routine for I-O Data Device, Inc. LANDISK.
 *
 * Initial version only to support LAN access; some
 * placeholder code from io_landisk.c left in with the
 * expectation of later SuperIO and PCMCIA access.
 */
/*
 * modified by kogiidena
 * 2005.03.03
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 */
#include <linux/init.h>
#include <linux/irq.h>
@@ -20,71 +18,27 @@
#include <linux/io.h>
#include <asm/landisk/iodata_landisk.h>

static void enable_landisk_irq(unsigned int irq);
static void disable_landisk_irq(unsigned int irq);

/* shutdown is same as "disable" */
#define shutdown_landisk_irq disable_landisk_irq

static void ack_landisk_irq(unsigned int irq);
static void end_landisk_irq(unsigned int irq);

static unsigned int startup_landisk_irq(unsigned int irq)
{
	enable_landisk_irq(irq);
	return 0;		/* never anything pending */
}

static void disable_landisk_irq(unsigned int irq)
{
	unsigned char val;
	unsigned char mask = 0xff ^ (0x01 << (irq - 5));

	/* Set the priority in IPR to 0 */
	val = ctrl_inb(PA_IMASK);
	val &= mask;
	ctrl_outb(val, PA_IMASK);
	ctrl_outb(ctrl_inb(PA_IMASK) & mask, PA_IMASK);
}

static void enable_landisk_irq(unsigned int irq)
{
	unsigned char val;
	unsigned char value = (0x01 << (irq - 5));

	/* Set priority in IPR back to original value */
	val = ctrl_inb(PA_IMASK);
	val |= value;
	ctrl_outb(val, PA_IMASK);
	ctrl_outb(ctrl_inb(PA_IMASK) | value, PA_IMASK);
}

static void ack_landisk_irq(unsigned int irq)
{
	disable_landisk_irq(irq);
}

static void end_landisk_irq(unsigned int irq)
{
	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
		enable_landisk_irq(irq);
}

static struct hw_interrupt_type landisk_irq_type = {
	.typename = "LANDISK IRQ",
	.startup = startup_landisk_irq,
	.shutdown = shutdown_landisk_irq,
	.enable = enable_landisk_irq,
	.disable = disable_landisk_irq,
	.ack = ack_landisk_irq,
	.end = end_landisk_irq
static struct irq_chip landisk_irq_chip __read_mostly = {
	.name		= "LANDISK",
	.mask		= disable_landisk_irq,
	.unmask		= enable_landisk_irq,
	.mask_ack	= disable_landisk_irq,
};

static void make_landisk_irq(unsigned int irq)
{
	disable_irq_nosync(irq);
	irq_desc[irq].chip = &landisk_irq_type;
	disable_landisk_irq(irq);
}

/*
 * Initialize IRQ setting
 */
@@ -92,6 +46,11 @@ void __init init_landisk_IRQ(void)
{
	int i;

	for (i = 5; i < 14; i++)
		make_landisk_irq(i);
	for (i = 5; i < 14; i++) {
		disable_irq_nosync(i);
		set_irq_chip_and_handler_name(i, &landisk_irq_chip,
					      handle_level_irq, "level");
		enable_landisk_irq(i);
	}
	ctrl_outb(0x00, PA_PWRINT_CLR);
}
+0 −346
Original line number Diff line number Diff line
/*
 * arch/sh/boards/landisk/landisk_pwb.c -- driver for the Power control switch.
 *
 * This driver will also support the I-O DATA Device, Inc. LANDISK Board.
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copylight (C) 2002 Atom Create Engineering Co., Ltd.
 *
 * LED control drive function added by kogiidena
 */
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/major.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>

#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/landisk/iodata_landisk.h>

#define SHUTDOWN_BTN_MINOR	1	/* Shutdown button device minor no. */
#define LED_MINOR	       21	/* LED minor no. */
#define BTN_MINOR	       22	/* BUTTON minor no. */
#define GIO_MINOR	       40	/* GIO minor no. */

static int openCnt;
static int openCntLED;
static int openCntGio;
static int openCntBtn;
static int landisk_btn;
static int landisk_btnctrlpid;
/*
 * Functions prototypes
 */

static int gio_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
		     unsigned long arg);

static int swdrv_open(struct inode *inode, struct file *filp)
{
	int minor;

	minor = MINOR(inode->i_rdev);
	filp->private_data = (void *)minor;

	if (minor == SHUTDOWN_BTN_MINOR) {
		if (openCnt > 0) {
			return -EALREADY;
		} else {
			openCnt++;
			return 0;
		}
	} else if (minor == LED_MINOR) {
		if (openCntLED > 0) {
			return -EALREADY;
		} else {
			openCntLED++;
			return 0;
		}
	} else if (minor == BTN_MINOR) {
		if (openCntBtn > 0) {
			return -EALREADY;
		} else {
			openCntBtn++;
			return 0;
		}
	} else if (minor == GIO_MINOR) {
		if (openCntGio > 0) {
			return -EALREADY;
		} else {
			openCntGio++;
			return 0;
		}
	}
	return -ENOENT;

}

static int swdrv_close(struct inode *inode, struct file *filp)
{
	int minor;

	minor = MINOR(inode->i_rdev);
	if (minor == SHUTDOWN_BTN_MINOR) {
		openCnt--;
	} else if (minor == LED_MINOR) {
		openCntLED--;
	} else if (minor == BTN_MINOR) {
		openCntBtn--;
	} else if (minor == GIO_MINOR) {
		openCntGio--;
	}
	return 0;
}

static int swdrv_read(struct file *filp, char *buff, size_t count,
		      loff_t * ppos)
{
	int minor;
	minor = (int)(filp->private_data);

	if (!access_ok(VERIFY_WRITE, (void *)buff, count))
		return -EFAULT;

	if (minor == SHUTDOWN_BTN_MINOR) {
		if (landisk_btn & 0x10) {
			put_user(1, buff);
			return 1;
		} else {
			return 0;
		}
	}
	return 0;
}

static int swdrv_write(struct file *filp, const char *buff, size_t count,
		       loff_t * ppos)
{
	int minor;
	minor = (int)(filp->private_data);

	if (minor == SHUTDOWN_BTN_MINOR) {
		return count;
	}
	return count;
}

static irqreturn_t sw_interrupt(int irq, void *dev_id)
{
	landisk_btn = (0x0ff & (~ctrl_inb(PA_STATUS)));
	disable_irq(IRQ_BUTTON);
	disable_irq(IRQ_POWER);
	ctrl_outb(0x00, PA_PWRINT_CLR);

	if (landisk_btnctrlpid != 0) {
		kill_proc(landisk_btnctrlpid, SIGUSR1, 1);
		landisk_btnctrlpid = 0;
	}

	return IRQ_HANDLED;
}

static const struct file_operations swdrv_fops = {
	.read = swdrv_read,	/* read */
	.write = swdrv_write,	/* write */
	.open = swdrv_open,	/* open */
	.release = swdrv_close,	/* release */
	.ioctl = gio_ioctl,	/* ioctl */

};

static char banner[] __initdata =
    KERN_INFO "LANDISK and USL-5P Button, LED and GIO driver initialized\n";

int __init swdrv_init(void)
{
	int error;

	printk("%s", banner);

	openCnt = 0;
	openCntLED = 0;
	openCntBtn = 0;
	openCntGio = 0;
	landisk_btn = 0;
	landisk_btnctrlpid = 0;

	if ((error = register_chrdev(SHUTDOWN_BTN_MAJOR, "swdrv", &swdrv_fops))) {
		printk(KERN_ERR
		       "Button, LED and GIO driver:Couldn't register driver, error=%d\n",
		       error);
		return 1;
	}

	if (request_irq(IRQ_POWER, sw_interrupt, 0, "SHUTDOWNSWITCH", NULL)) {
		printk(KERN_ERR "Unable to get IRQ 11.\n");
		return 1;
	}
	if (request_irq(IRQ_BUTTON, sw_interrupt, 0, "USL-5P BUTTON", NULL)) {
		printk(KERN_ERR "Unable to get IRQ 12.\n");
		return 1;
	}
	ctrl_outb(0x00, PA_PWRINT_CLR);

	return 0;
}

module_init(swdrv_init);

/*
 * gio driver
 *
 */

#include <asm/landisk/gio.h>

static int gio_ioctl(struct inode *inode, struct file *filp,
		     unsigned int cmd, unsigned long arg)
{
	int minor;
	unsigned int data, mask;
	static unsigned int addr = 0;

	minor = (int)(filp->private_data);

	/* access control */
	if (minor == GIO_MINOR) {
		;
	} else if (minor == LED_MINOR) {
		if (((cmd & 0x0ff) >= 9) && ((cmd & 0x0ff) < 20)) {
			;
		} else {
			return -EINVAL;
		}
	} else if (minor == BTN_MINOR) {
		if (((cmd & 0x0ff) >= 20) && ((cmd & 0x0ff) < 30)) {
			;
		} else {
			return -EINVAL;
		}
	} else {
		return -EINVAL;
	}

	if (cmd & 0x01) {	/* write */
		if (copy_from_user(&data, (int *)arg, sizeof(int))) {
			return -EFAULT;
		}
	}

	switch (cmd) {
	case GIODRV_IOCSGIOSETADDR:	/* addres set */
		addr = data;
		break;

	case GIODRV_IOCSGIODATA1:	/* write byte */
		ctrl_outb((unsigned char)(0x0ff & data), addr);
		break;

	case GIODRV_IOCSGIODATA2:	/* write word */
		if (addr & 0x01) {
			return -EFAULT;
		}
		ctrl_outw((unsigned short int)(0x0ffff & data), addr);
		break;

	case GIODRV_IOCSGIODATA4:	/* write long */
		if (addr & 0x03) {
			return -EFAULT;
		}
		ctrl_outl(data, addr);
		break;

	case GIODRV_IOCGGIODATA1:	/* read byte */
		data = ctrl_inb(addr);
		break;

	case GIODRV_IOCGGIODATA2:	/* read word */
		if (addr & 0x01) {
			return -EFAULT;
		}
		data = ctrl_inw(addr);
		break;

	case GIODRV_IOCGGIODATA4:	/* read long */
		if (addr & 0x03) {
			return -EFAULT;
		}
		data = ctrl_inl(addr);
		break;
	case GIODRV_IOCSGIO_LED:	/* write */
		mask = ((data & 0x00ffffff) << 8)
		    | ((data & 0x0000ffff) << 16)
		    | ((data & 0x000000ff) << 24);
		landisk_ledparam = data & (~mask);
		if (landisk_arch == 0) {	/* arch == landisk */
			landisk_ledparam &= 0x03030303;
			mask = (~(landisk_ledparam >> 22)) & 0x000c;
			landisk_ledparam |= mask;
		} else {	                /* arch == usl-5p */
			mask = (landisk_ledparam >> 24) & 0x0001;
			landisk_ledparam |= mask;
			landisk_ledparam &= 0x007f7f7f;
		}
		landisk_ledparam |= 0x80;
		break;
	case GIODRV_IOCGGIO_LED:	/* read */
		data = landisk_ledparam;
		if (landisk_arch == 0) {	/* arch == landisk */
			data &= 0x03030303;
		} else {	                /* arch == usl-5p */
			;
		}
		data &= (~0x080);
		break;
	case GIODRV_IOCSGIO_BUZZER:	/* write */
		landisk_buzzerparam = data;
		landisk_ledparam |= 0x80;
		break;
	case GIODRV_IOCGGIO_LANDISK:	/* read */
		data = landisk_arch & 0x01;
		break;
	case GIODRV_IOCGGIO_BTN:	/* read */
		data = (0x0ff & ctrl_inb(PA_PWRINT_CLR));
		data <<= 8;
		data |= (0x0ff & ctrl_inb(PA_IMASK));
		data <<= 8;
		data |= (0x0ff & landisk_btn);
		data <<= 8;
		data |= (0x0ff & (~ctrl_inb(PA_STATUS)));
		break;
	case GIODRV_IOCSGIO_BTNPID:	/* write */
		landisk_btnctrlpid = data;
		landisk_btn = 0;
		if (irq_desc[IRQ_BUTTON].depth) {
			enable_irq(IRQ_BUTTON);
		}
		if (irq_desc[IRQ_POWER].depth) {
			enable_irq(IRQ_POWER);
		}
		break;
	case GIODRV_IOCGGIO_BTNPID:	/* read */
		data = landisk_btnctrlpid;
		break;
	default:
		return -EFAULT;
		break;
	}

	if ((cmd & 0x01) == 0) {	/* read */
		if (copy_to_user((int *)arg, &data, sizeof(int))) {
			return -EFAULT;
		}
	}
	return 0;
}
Loading