162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/drivers/hil/hilkbd.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
662306a36Sopenharmony_ci *  Copyright (C) 1999 Matthew Wilcox <willy@infradead.org>
762306a36Sopenharmony_ci *  Copyright (C) 1999-2007 Helge Deller <deller@gmx.de>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *  Very basic HP Human Interface Loop (HIL) driver.
1062306a36Sopenharmony_ci *  This driver handles the keyboard on HP300 (m68k) and on some
1162306a36Sopenharmony_ci *  HP700 (parisc) series machines.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/pci_ids.h>
1562306a36Sopenharmony_ci#include <linux/ioport.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/errno.h>
1862306a36Sopenharmony_ci#include <linux/input.h>
1962306a36Sopenharmony_ci#include <linux/init.h>
2062306a36Sopenharmony_ci#include <linux/interrupt.h>
2162306a36Sopenharmony_ci#include <linux/hil.h>
2262306a36Sopenharmony_ci#include <linux/io.h>
2362306a36Sopenharmony_ci#include <linux/sched.h>
2462306a36Sopenharmony_ci#include <linux/spinlock.h>
2562306a36Sopenharmony_ci#include <asm/irq.h>
2662306a36Sopenharmony_ci#ifdef CONFIG_HP300
2762306a36Sopenharmony_ci#include <asm/hwtest.h>
2862306a36Sopenharmony_ci#endif
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ciMODULE_AUTHOR("Philip Blundell, Matthew Wilcox, Helge Deller");
3262306a36Sopenharmony_ciMODULE_DESCRIPTION("HIL keyboard driver (basic functionality)");
3362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#if defined(CONFIG_PARISC)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci #include <asm/io.h>
3962306a36Sopenharmony_ci #include <asm/hardware.h>
4062306a36Sopenharmony_ci #include <asm/parisc-device.h>
4162306a36Sopenharmony_ci static unsigned long hil_base;	/* HPA for the HIL device */
4262306a36Sopenharmony_ci static unsigned int hil_irq;
4362306a36Sopenharmony_ci #define HILBASE		hil_base /* HPPA (parisc) port address */
4462306a36Sopenharmony_ci #define HIL_DATA		0x800
4562306a36Sopenharmony_ci #define HIL_CMD		0x801
4662306a36Sopenharmony_ci #define HIL_IRQ		hil_irq
4762306a36Sopenharmony_ci #define hil_readb(p)		gsc_readb(p)
4862306a36Sopenharmony_ci #define hil_writeb(v,p)	gsc_writeb((v),(p))
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#elif defined(CONFIG_HP300)
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci #define HILBASE		0xf0428000UL /* HP300 (m68k) port address */
5362306a36Sopenharmony_ci #define HIL_DATA		0x1
5462306a36Sopenharmony_ci #define HIL_CMD		0x3
5562306a36Sopenharmony_ci #define HIL_IRQ		2
5662306a36Sopenharmony_ci #define hil_readb(p)		readb((const volatile void __iomem *)(p))
5762306a36Sopenharmony_ci #define hil_writeb(v, p)	writeb((v), (volatile void __iomem *)(p))
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#else
6062306a36Sopenharmony_ci#error "HIL is not supported on this platform"
6162306a36Sopenharmony_ci#endif
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/* HIL helper functions */
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#define hil_busy()              (hil_readb(HILBASE + HIL_CMD) & HIL_BUSY)
6862306a36Sopenharmony_ci#define hil_data_available()    (hil_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY)
6962306a36Sopenharmony_ci#define hil_status()            (hil_readb(HILBASE + HIL_CMD))
7062306a36Sopenharmony_ci#define hil_command(x)          do { hil_writeb((x), HILBASE + HIL_CMD); } while (0)
7162306a36Sopenharmony_ci#define hil_read_data()         (hil_readb(HILBASE + HIL_DATA))
7262306a36Sopenharmony_ci#define hil_write_data(x)       do { hil_writeb((x), HILBASE + HIL_DATA); } while (0)
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/* HIL constants */
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define	HIL_BUSY		0x02
7762306a36Sopenharmony_ci#define	HIL_DATA_RDY		0x01
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#define	HIL_SETARD		0xA0		/* set auto-repeat delay */
8062306a36Sopenharmony_ci#define	HIL_SETARR		0xA2		/* set auto-repeat rate */
8162306a36Sopenharmony_ci#define	HIL_SETTONE		0xA3		/* set tone generator */
8262306a36Sopenharmony_ci#define	HIL_CNMT		0xB2		/* clear nmi */
8362306a36Sopenharmony_ci#define	HIL_INTON		0x5C		/* Turn on interrupts. */
8462306a36Sopenharmony_ci#define	HIL_INTOFF		0x5D		/* Turn off interrupts. */
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#define	HIL_READKBDSADR		0xF9
8762306a36Sopenharmony_ci#define	HIL_WRITEKBDSADR	0xE9
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] __read_mostly =
9062306a36Sopenharmony_ci	{ HIL_KEYCODES_SET1 };
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/* HIL structure */
9362306a36Sopenharmony_cistatic struct {
9462306a36Sopenharmony_ci	struct input_dev *dev;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	unsigned int curdev;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	unsigned char s;
9962306a36Sopenharmony_ci	unsigned char c;
10062306a36Sopenharmony_ci	int valid;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	unsigned char data[16];
10362306a36Sopenharmony_ci	unsigned int ptr;
10462306a36Sopenharmony_ci	spinlock_t lock;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	void *dev_id;	/* native bus device */
10762306a36Sopenharmony_ci} hil_dev;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic void poll_finished(void)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	int down;
11362306a36Sopenharmony_ci	int key;
11462306a36Sopenharmony_ci	unsigned char scode;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	switch (hil_dev.data[0]) {
11762306a36Sopenharmony_ci	case 0x40:
11862306a36Sopenharmony_ci		down = (hil_dev.data[1] & 1) == 0;
11962306a36Sopenharmony_ci		scode = hil_dev.data[1] >> 1;
12062306a36Sopenharmony_ci		key = hphilkeyb_keycode[scode];
12162306a36Sopenharmony_ci		input_report_key(hil_dev.dev, key, down);
12262306a36Sopenharmony_ci		break;
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci	hil_dev.curdev = 0;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic inline void handle_status(unsigned char s, unsigned char c)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	if (c & 0x8) {
13162306a36Sopenharmony_ci		/* End of block */
13262306a36Sopenharmony_ci		if (c & 0x10)
13362306a36Sopenharmony_ci			poll_finished();
13462306a36Sopenharmony_ci	} else {
13562306a36Sopenharmony_ci		if (c & 0x10) {
13662306a36Sopenharmony_ci			if (hil_dev.curdev)
13762306a36Sopenharmony_ci				poll_finished();  /* just in case */
13862306a36Sopenharmony_ci			hil_dev.curdev = c & 7;
13962306a36Sopenharmony_ci			hil_dev.ptr = 0;
14062306a36Sopenharmony_ci		}
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic inline void handle_data(unsigned char s, unsigned char c)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	if (hil_dev.curdev) {
14862306a36Sopenharmony_ci		hil_dev.data[hil_dev.ptr++] = c;
14962306a36Sopenharmony_ci		hil_dev.ptr &= 15;
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/* handle HIL interrupts */
15562306a36Sopenharmony_cistatic irqreturn_t hil_interrupt(int irq, void *handle)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	unsigned char s, c;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	s = hil_status();
16062306a36Sopenharmony_ci	c = hil_read_data();
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	switch (s >> 4) {
16362306a36Sopenharmony_ci	case 0x5:
16462306a36Sopenharmony_ci		handle_status(s, c);
16562306a36Sopenharmony_ci		break;
16662306a36Sopenharmony_ci	case 0x6:
16762306a36Sopenharmony_ci		handle_data(s, c);
16862306a36Sopenharmony_ci		break;
16962306a36Sopenharmony_ci	case 0x4:
17062306a36Sopenharmony_ci		hil_dev.s = s;
17162306a36Sopenharmony_ci		hil_dev.c = c;
17262306a36Sopenharmony_ci		mb();
17362306a36Sopenharmony_ci		hil_dev.valid = 1;
17462306a36Sopenharmony_ci		break;
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci	return IRQ_HANDLED;
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci/* send a command to the HIL */
18162306a36Sopenharmony_cistatic void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	unsigned long flags;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	spin_lock_irqsave(&hil_dev.lock, flags);
18662306a36Sopenharmony_ci	while (hil_busy())
18762306a36Sopenharmony_ci		/* wait */;
18862306a36Sopenharmony_ci	hil_command(cmd);
18962306a36Sopenharmony_ci	while (len--) {
19062306a36Sopenharmony_ci		while (hil_busy())
19162306a36Sopenharmony_ci			/* wait */;
19262306a36Sopenharmony_ci		hil_write_data(*(data++));
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci	spin_unlock_irqrestore(&hil_dev.lock, flags);
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/* initialize HIL */
19962306a36Sopenharmony_cistatic int hil_keyb_init(void)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	unsigned char c;
20262306a36Sopenharmony_ci	unsigned int i, kbid;
20362306a36Sopenharmony_ci	wait_queue_head_t hil_wait;
20462306a36Sopenharmony_ci	int err;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	if (hil_dev.dev)
20762306a36Sopenharmony_ci		return -ENODEV; /* already initialized */
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	init_waitqueue_head(&hil_wait);
21062306a36Sopenharmony_ci	spin_lock_init(&hil_dev.lock);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	hil_dev.dev = input_allocate_device();
21362306a36Sopenharmony_ci	if (!hil_dev.dev)
21462306a36Sopenharmony_ci		return -ENOMEM;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	err = request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id);
21762306a36Sopenharmony_ci	if (err) {
21862306a36Sopenharmony_ci		printk(KERN_ERR "HIL: Can't get IRQ\n");
21962306a36Sopenharmony_ci		goto err1;
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	/* Turn on interrupts */
22362306a36Sopenharmony_ci	hil_do(HIL_INTON, NULL, 0);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	/* Look for keyboards */
22662306a36Sopenharmony_ci	hil_dev.valid = 0;	/* clear any pending data */
22762306a36Sopenharmony_ci	hil_do(HIL_READKBDSADR, NULL, 0);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	wait_event_interruptible_timeout(hil_wait, hil_dev.valid, 3 * HZ);
23062306a36Sopenharmony_ci	if (!hil_dev.valid)
23162306a36Sopenharmony_ci		printk(KERN_WARNING "HIL: timed out, assuming no keyboard present\n");
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	c = hil_dev.c;
23462306a36Sopenharmony_ci	hil_dev.valid = 0;
23562306a36Sopenharmony_ci	if (c == 0) {
23662306a36Sopenharmony_ci		kbid = -1;
23762306a36Sopenharmony_ci		printk(KERN_WARNING "HIL: no keyboard present\n");
23862306a36Sopenharmony_ci	} else {
23962306a36Sopenharmony_ci		kbid = ffz(~c);
24062306a36Sopenharmony_ci		printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid);
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	/* set it to raw mode */
24462306a36Sopenharmony_ci	c = 0;
24562306a36Sopenharmony_ci	hil_do(HIL_WRITEKBDSADR, &c, 1);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++)
24862306a36Sopenharmony_ci		if (hphilkeyb_keycode[i] != KEY_RESERVED)
24962306a36Sopenharmony_ci			__set_bit(hphilkeyb_keycode[i], hil_dev.dev->keybit);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	hil_dev.dev->evbit[0]	= BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
25262306a36Sopenharmony_ci	hil_dev.dev->ledbit[0]	= BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
25362306a36Sopenharmony_ci		BIT_MASK(LED_SCROLLL);
25462306a36Sopenharmony_ci	hil_dev.dev->keycodemax	= HIL_KEYCODES_SET1_TBLSIZE;
25562306a36Sopenharmony_ci	hil_dev.dev->keycodesize= sizeof(hphilkeyb_keycode[0]);
25662306a36Sopenharmony_ci	hil_dev.dev->keycode	= hphilkeyb_keycode;
25762306a36Sopenharmony_ci	hil_dev.dev->name	= "HIL keyboard";
25862306a36Sopenharmony_ci	hil_dev.dev->phys	= "hpkbd/input0";
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	hil_dev.dev->id.bustype	= BUS_HIL;
26162306a36Sopenharmony_ci	hil_dev.dev->id.vendor	= PCI_VENDOR_ID_HP;
26262306a36Sopenharmony_ci	hil_dev.dev->id.product	= 0x0001;
26362306a36Sopenharmony_ci	hil_dev.dev->id.version	= 0x0010;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	err = input_register_device(hil_dev.dev);
26662306a36Sopenharmony_ci	if (err) {
26762306a36Sopenharmony_ci		printk(KERN_ERR "HIL: Can't register device\n");
26862306a36Sopenharmony_ci		goto err2;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n",
27262306a36Sopenharmony_ci	       hil_dev.dev->name, kbid, HILBASE, HIL_IRQ);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	return 0;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cierr2:
27762306a36Sopenharmony_ci	hil_do(HIL_INTOFF, NULL, 0);
27862306a36Sopenharmony_ci	free_irq(HIL_IRQ, hil_dev.dev_id);
27962306a36Sopenharmony_cierr1:
28062306a36Sopenharmony_ci	input_free_device(hil_dev.dev);
28162306a36Sopenharmony_ci	hil_dev.dev = NULL;
28262306a36Sopenharmony_ci	return err;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic void hil_keyb_exit(void)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	if (HIL_IRQ)
28862306a36Sopenharmony_ci		free_irq(HIL_IRQ, hil_dev.dev_id);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	/* Turn off interrupts */
29162306a36Sopenharmony_ci	hil_do(HIL_INTOFF, NULL, 0);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	input_unregister_device(hil_dev.dev);
29462306a36Sopenharmony_ci	hil_dev.dev = NULL;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci#if defined(CONFIG_PARISC)
29862306a36Sopenharmony_cistatic int __init hil_probe_chip(struct parisc_device *dev)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	/* Only allow one HIL keyboard */
30162306a36Sopenharmony_ci	if (hil_dev.dev)
30262306a36Sopenharmony_ci		return -ENODEV;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (!dev->irq) {
30562306a36Sopenharmony_ci		printk(KERN_WARNING "HIL: IRQ not found for HIL bus at 0x%p\n",
30662306a36Sopenharmony_ci			(void *)dev->hpa.start);
30762306a36Sopenharmony_ci		return -ENODEV;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	hil_base = dev->hpa.start;
31162306a36Sopenharmony_ci	hil_irq  = dev->irq;
31262306a36Sopenharmony_ci	hil_dev.dev_id = dev;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	printk(KERN_INFO "Found HIL bus at 0x%08lx, IRQ %d\n", hil_base, hil_irq);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	return hil_keyb_init();
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic void __exit hil_remove_chip(struct parisc_device *dev)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	hil_keyb_exit();
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic const struct parisc_device_id hil_tbl[] __initconst = {
32562306a36Sopenharmony_ci	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00073 },
32662306a36Sopenharmony_ci	{ 0, }
32762306a36Sopenharmony_ci};
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci#if 0
33062306a36Sopenharmony_ci/* Disabled to avoid conflicts with the HP SDC HIL drivers */
33162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(parisc, hil_tbl);
33262306a36Sopenharmony_ci#endif
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic struct parisc_driver hil_driver __refdata = {
33562306a36Sopenharmony_ci	.name		= "hil",
33662306a36Sopenharmony_ci	.id_table	= hil_tbl,
33762306a36Sopenharmony_ci	.probe		= hil_probe_chip,
33862306a36Sopenharmony_ci	.remove		= __exit_p(hil_remove_chip),
33962306a36Sopenharmony_ci};
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic int __init hil_init(void)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	return register_parisc_driver(&hil_driver);
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic void __exit hil_exit(void)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	unregister_parisc_driver(&hil_driver);
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci#else /* !CONFIG_PARISC */
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic int __init hil_init(void)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	int error;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	/* Only allow one HIL keyboard */
35862306a36Sopenharmony_ci	if (hil_dev.dev)
35962306a36Sopenharmony_ci		return -EBUSY;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (!MACH_IS_HP300)
36262306a36Sopenharmony_ci		return -ENODEV;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (!hwreg_present((void *)(HILBASE + HIL_DATA))) {
36562306a36Sopenharmony_ci		printk(KERN_ERR "HIL: hardware register was not found\n");
36662306a36Sopenharmony_ci		return -ENODEV;
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	if (!request_region(HILBASE + HIL_DATA, 2, "hil")) {
37062306a36Sopenharmony_ci		printk(KERN_ERR "HIL: IOPORT region already used\n");
37162306a36Sopenharmony_ci		return -EIO;
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	error = hil_keyb_init();
37562306a36Sopenharmony_ci	if (error) {
37662306a36Sopenharmony_ci		release_region(HILBASE + HIL_DATA, 2);
37762306a36Sopenharmony_ci		return error;
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	return 0;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic void __exit hil_exit(void)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	hil_keyb_exit();
38662306a36Sopenharmony_ci	release_region(HILBASE + HIL_DATA, 2);
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci#endif /* CONFIG_PARISC */
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cimodule_init(hil_init);
39262306a36Sopenharmony_cimodule_exit(hil_exit);
393