cregit-Linux how code gets into the kernel

Release 4.11 drivers/input/keyboard/hilkbd.c

/*
 *  linux/drivers/hil/hilkbd.c
 *
 *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
 *  Copyright (C) 1999 Matthew Wilcox <willy@bofh.ai>
 *  Copyright (C) 1999-2007 Helge Deller <deller@gmx.de>
 *
 *  Very basic HP Human Interface Loop (HIL) driver.
 *  This driver handles the keyboard on HP300 (m68k) and on some
 *  HP700 (parisc) series machines.
 *
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License version 2.  See the file COPYING in the main directory of this
 * archive for more details.
 */

#include <linux/pci_ids.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hil.h>
#include <linux/io.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <asm/irq.h>
#ifdef CONFIG_HP300
#include <asm/hwtest.h>
#endif


MODULE_AUTHOR("Philip Blundell, Matthew Wilcox, Helge Deller");
MODULE_DESCRIPTION("HIL keyboard driver (basic functionality)");
MODULE_LICENSE("GPL v2");


#if defined(CONFIG_PARISC)

 #include <asm/io.h>
 #include <asm/hardware.h>
 #include <asm/parisc-device.h>
 
static unsigned long hil_base;	
/* HPA for the HIL device */
 
static unsigned int hil_irq;
 
#define HILBASE		hil_base 
/* HPPA (parisc) port address */
 
#define HIL_DATA		0x800
 
#define HIL_CMD		0x801
 
#define HIL_IRQ		hil_irq
 
#define hil_readb(p)		gsc_readb(p)
 
#define hil_writeb(v,p)	gsc_writeb((v),(p))

#elif defined(CONFIG_HP300)

 
#define HILBASE		0xf0428000UL 
/* HP300 (m68k) port address */
 
#define HIL_DATA		0x1
 
#define HIL_CMD		0x3
 
#define HIL_IRQ		2
 
#define hil_readb(p)		readb(p)
 
#define hil_writeb(v,p)	writeb((v),(p))

#else
#error "HIL is not supported on this platform"
#endif



/* HIL helper functions */


#define hil_busy()              (hil_readb(HILBASE + HIL_CMD) & HIL_BUSY)

#define hil_data_available()    (hil_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY)

#define hil_status()            (hil_readb(HILBASE + HIL_CMD))

#define hil_command(x)          do { hil_writeb((x), HILBASE + HIL_CMD); } while (0)

#define hil_read_data()         (hil_readb(HILBASE + HIL_DATA))

#define hil_write_data(x)       do { hil_writeb((x), HILBASE + HIL_DATA); } while (0)

/* HIL constants */


#define	HIL_BUSY		0x02

#define	HIL_DATA_RDY		0x01


#define	HIL_SETARD		0xA0		
/* set auto-repeat delay */

#define	HIL_SETARR		0xA2		
/* set auto-repeat rate */

#define	HIL_SETTONE		0xA3		
/* set tone generator */

#define	HIL_CNMT		0xB2		
/* clear nmi */

#define	HIL_INTON		0x5C		
/* Turn on interrupts. */

#define	HIL_INTOFF		0x5D		
/* Turn off interrupts. */


#define	HIL_READKBDSADR		0xF9

#define	HIL_WRITEKBDSADR	0xE9


static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] __read_mostly =
	{ HIL_KEYCODES_SET1 };

/* HIL structure */
static struct {
	
struct input_dev *dev;

	
unsigned int curdev;

	
unsigned char s;
	
unsigned char c;
	
int valid;

	
unsigned char data[16];
	
unsigned int ptr;
	
spinlock_t lock;

	
void *dev_id;	/* native bus device */
} 
hil_dev;



static void poll_finished(void) { int down; int key; unsigned char scode; switch (hil_dev.data[0]) { case 0x40: down = (hil_dev.data[1] & 1) == 0; scode = hil_dev.data[1] >> 1; key = hphilkeyb_keycode[scode]; input_report_key(hil_dev.dev, key, down); break; } hil_dev.curdev = 0; }

Contributors

PersonTokensPropCommitsCommitProp
Helge Deller83100.00%1100.00%
Total83100.00%1100.00%


static inline void handle_status(unsigned char s, unsigned char c) { if (c & 0x8) { /* End of block */ if (c & 0x10) poll_finished(); } else { if (c & 0x10) { if (hil_dev.curdev) poll_finished(); /* just in case */ hil_dev.curdev = c & 7; hil_dev.ptr = 0; } } }

Contributors

PersonTokensPropCommitsCommitProp
Helge Deller68100.00%1100.00%
Total68100.00%1100.00%


static inline void handle_data(unsigned char s, unsigned char c) { if (hil_dev.curdev) { hil_dev.data[hil_dev.ptr++] = c; hil_dev.ptr &= 15; } }

Contributors

PersonTokensPropCommitsCommitProp
Helge Deller41100.00%1100.00%
Total41100.00%1100.00%

/* handle HIL interrupts */
static irqreturn_t hil_interrupt(int irq, void *handle) { unsigned char s, c; s = hil_status(); c = hil_read_data(); switch (s >> 4) { case 0x5: handle_status(s, c); break; case 0x6: handle_data(s, c); break; case 0x4: hil_dev.s = s; hil_dev.c = c; mb(); hil_dev.valid = 1; break; } return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
Helge Deller87100.00%1100.00%
Total87100.00%1100.00%

/* send a command to the HIL */
static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len) { unsigned long flags; spin_lock_irqsave(&hil_dev.lock, flags); while (hil_busy()) /* wait */; hil_command(cmd); while (len--) { while (hil_busy()) /* wait */; hil_write_data(*(data++)); } spin_unlock_irqrestore(&hil_dev.lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Helge Deller78100.00%1100.00%
Total78100.00%1100.00%

/* initialize HIL */
static int hil_keyb_init(void) { unsigned char c; unsigned int i, kbid; wait_queue_head_t hil_wait; int err; if (hil_dev.dev) return -ENODEV; /* already initialized */ init_waitqueue_head(&hil_wait); spin_lock_init(&hil_dev.lock); hil_dev.dev = input_allocate_device(); if (!hil_dev.dev) return -ENOMEM; err = request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id); if (err) { printk(KERN_ERR "HIL: Can't get IRQ\n"); goto err1; } /* Turn on interrupts */ hil_do(HIL_INTON, NULL, 0); /* Look for keyboards */ hil_dev.valid = 0; /* clear any pending data */ hil_do(HIL_READKBDSADR, NULL, 0); wait_event_interruptible_timeout(hil_wait, hil_dev.valid, 3 * HZ); if (!hil_dev.valid) printk(KERN_WARNING "HIL: timed out, assuming no keyboard present\n"); c = hil_dev.c; hil_dev.valid = 0; if (c == 0) { kbid = -1; printk(KERN_WARNING "HIL: no keyboard present\n"); } else { kbid = ffz(~c); printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid); } /* set it to raw mode */ c = 0; hil_do(HIL_WRITEKBDSADR, &c, 1); for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++) if (hphilkeyb_keycode[i] != KEY_RESERVED) __set_bit(hphilkeyb_keycode[i], hil_dev.dev->keybit); hil_dev.dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); hil_dev.dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | BIT_MASK(LED_SCROLLL); hil_dev.dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; hil_dev.dev->keycodesize= sizeof(hphilkeyb_keycode[0]); hil_dev.dev->keycode = hphilkeyb_keycode; hil_dev.dev->name = "HIL keyboard"; hil_dev.dev->phys = "hpkbd/input0"; hil_dev.dev->id.bustype = BUS_HIL; hil_dev.dev->id.vendor = PCI_VENDOR_ID_HP; hil_dev.dev->id.product = 0x0001; hil_dev.dev->id.version = 0x0010; err = input_register_device(hil_dev.dev); if (err) { printk(KERN_ERR "HIL: Can't register device\n"); goto err2; } printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n", hil_dev.dev->name, kbid, HILBASE, HIL_IRQ); return 0; err2: hil_do(HIL_INTOFF, NULL, 0); free_irq(HIL_IRQ, hil_dev.dev_id); err1: input_free_device(hil_dev.dev); hil_dev.dev = NULL; return err; }

Contributors

PersonTokensPropCommitsCommitProp
Helge Deller40186.24%466.67%
Cyrill V. Gorcunov5912.69%116.67%
Jiri Slaby51.08%116.67%
Total465100.00%6100.00%


static void hil_keyb_exit(void) { if (HIL_IRQ) free_irq(HIL_IRQ, hil_dev.dev_id); /* Turn off interrupts */ hil_do(HIL_INTOFF, NULL, 0); input_unregister_device(hil_dev.dev); hil_dev.dev = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Cyrill V. Gorcunov2556.82%133.33%
Helge Deller1943.18%266.67%
Total44100.00%3100.00%

#if defined(CONFIG_PARISC)
static int hil_probe_chip(struct parisc_device *dev) { /* Only allow one HIL keyboard */ if (hil_dev.dev) return -ENODEV; if (!dev->irq) { printk(KERN_WARNING "HIL: IRQ not found for HIL bus at 0x%p\n", (void *)dev->hpa.start); return -ENODEV; } hil_base = dev->hpa.start; hil_irq = dev->irq; hil_dev.dev_id = dev; printk(KERN_INFO "Found HIL bus at 0x%08lx, IRQ %d\n", hil_base, hil_irq); return hil_keyb_init(); }

Contributors

PersonTokensPropCommitsCommitProp
Helge Deller8195.29%266.67%
Matthew Wilcox44.71%133.33%
Total85100.00%3100.00%


static int hil_remove_chip(struct parisc_device *dev) { hil_keyb_exit(); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Helge Deller17100.00%1100.00%
Total17100.00%1100.00%

static struct parisc_device_id hil_tbl[] = { { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00073 }, { 0, } }; #if 0 /* Disabled to avoid conflicts with the HP SDC HIL drivers */ MODULE_DEVICE_TABLE(parisc, hil_tbl); #endif static struct parisc_driver hil_driver = { .name = "hil", .id_table = hil_tbl, .probe = hil_probe_chip, .remove = hil_remove_chip, };
static int __init hil_init(void) { return register_parisc_driver(&hil_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Helge Deller16100.00%1100.00%
Total16100.00%1100.00%


static void __exit hil_exit(void) { unregister_parisc_driver(&hil_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Helge Deller15100.00%2100.00%
Total15100.00%2100.00%

#else /* !CONFIG_PARISC */
static int __init hil_init(void) { int error; /* Only allow one HIL keyboard */ if (hil_dev.dev) return -EBUSY; if (!MACH_IS_HP300) return -ENODEV; if (!hwreg_present((void *)(HILBASE + HIL_DATA))) { printk(KERN_ERR "HIL: hardware register was not found\n"); return -ENODEV; } if (!request_region(HILBASE + HIL_DATA, 2, "hil")) { printk(KERN_ERR "HIL: IOPORT region already used\n"); return -EIO; } error = hil_keyb_init(); if (error) { release_region(HILBASE + HIL_DATA, 2); return error; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Helge Deller112100.00%3100.00%
Total112100.00%3100.00%


static void __exit hil_exit(void) { hil_keyb_exit(); release_region(HILBASE + HIL_DATA, 2); }

Contributors

PersonTokensPropCommitsCommitProp
Helge Deller21100.00%2100.00%
Total21100.00%2100.00%

#endif /* CONFIG_PARISC */ module_init(hil_init); module_exit(hil_exit);

Overall Contributors

PersonTokensPropCommitsCommitProp
Helge Deller140392.36%433.33%
Cyrill V. Gorcunov865.66%18.33%
Al Viro140.92%18.33%
Matthew Wilcox60.39%325.00%
Jiri Slaby50.33%18.33%
Alexey Dobriyan30.20%18.33%
Geert Uytterhoeven20.13%18.33%
Total1519100.00%12100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.