mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 22:02:02 +00:00
Input: hilkbd - fix crash when removing hilkbd module
On parisc machines, which don't have HIL, removing the hilkbd module panics the kernel. Fix this by adding proper implementations for the probe and remove functions to the parisc_driver structure. A few functions were renamed to clean up the code and make it easier readable. Disable the MODULE_DEVICE_TABLE() macro on parisc since the kernel module autoloader should instead prefer the hp_sdc driver which takes care of full HIL support, including HIL mouse and HIL tablets. [dtor@mail.ru: fix some section markups] Signed-off-by: Helge Deller <deller@gmx.de> Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
This commit is contained in:
parent
adcb523eb3
commit
b0ecc73094
1 changed files with 82 additions and 62 deletions
|
@ -198,45 +198,28 @@ static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* initialise HIL */
|
/* initialize HIL */
|
||||||
static int __init
|
static int __devinit hil_keyb_init(void)
|
||||||
hil_keyb_init(void)
|
|
||||||
{
|
{
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
unsigned int i, kbid;
|
unsigned int i, kbid;
|
||||||
wait_queue_head_t hil_wait;
|
wait_queue_head_t hil_wait;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (hil_dev.dev) {
|
if (hil_dev.dev)
|
||||||
return -ENODEV; /* already initialized */
|
return -ENODEV; /* already initialized */
|
||||||
}
|
|
||||||
|
|
||||||
|
init_waitqueue_head(&hil_wait);
|
||||||
spin_lock_init(&hil_dev.lock);
|
spin_lock_init(&hil_dev.lock);
|
||||||
|
|
||||||
hil_dev.dev = input_allocate_device();
|
hil_dev.dev = input_allocate_device();
|
||||||
if (!hil_dev.dev)
|
if (!hil_dev.dev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
#if defined(CONFIG_HP300)
|
|
||||||
if (!MACH_IS_HP300) {
|
|
||||||
err = -ENODEV;
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
if (!hwreg_present((void *)(HILBASE + HIL_DATA))) {
|
|
||||||
printk(KERN_ERR "HIL: hardware register was not found\n");
|
|
||||||
err = -ENODEV;
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
if (!request_region(HILBASE + HIL_DATA, 2, "hil")) {
|
|
||||||
printk(KERN_ERR "HIL: IOPORT region already used\n");
|
|
||||||
err = -EIO;
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
err = request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id);
|
err = request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id);
|
||||||
if (err) {
|
if (err) {
|
||||||
printk(KERN_ERR "HIL: Can't get IRQ\n");
|
printk(KERN_ERR "HIL: Can't get IRQ\n");
|
||||||
goto err2;
|
goto err1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Turn on interrupts */
|
/* Turn on interrupts */
|
||||||
|
@ -246,11 +229,9 @@ hil_keyb_init(void)
|
||||||
hil_dev.valid = 0; /* clear any pending data */
|
hil_dev.valid = 0; /* clear any pending data */
|
||||||
hil_do(HIL_READKBDSADR, NULL, 0);
|
hil_do(HIL_READKBDSADR, NULL, 0);
|
||||||
|
|
||||||
init_waitqueue_head(&hil_wait);
|
wait_event_interruptible_timeout(hil_wait, hil_dev.valid, 3 * HZ);
|
||||||
wait_event_interruptible_timeout(hil_wait, hil_dev.valid, 3*HZ);
|
if (!hil_dev.valid)
|
||||||
if (!hil_dev.valid) {
|
|
||||||
printk(KERN_WARNING "HIL: timed out, assuming no keyboard present\n");
|
printk(KERN_WARNING "HIL: timed out, assuming no keyboard present\n");
|
||||||
}
|
|
||||||
|
|
||||||
c = hil_dev.c;
|
c = hil_dev.c;
|
||||||
hil_dev.valid = 0;
|
hil_dev.valid = 0;
|
||||||
|
@ -268,7 +249,7 @@ hil_keyb_init(void)
|
||||||
|
|
||||||
for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++)
|
for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++)
|
||||||
if (hphilkeyb_keycode[i] != KEY_RESERVED)
|
if (hphilkeyb_keycode[i] != KEY_RESERVED)
|
||||||
set_bit(hphilkeyb_keycode[i], hil_dev.dev->keybit);
|
__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->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
|
||||||
hil_dev.dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
|
hil_dev.dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
|
||||||
|
@ -287,34 +268,45 @@ hil_keyb_init(void)
|
||||||
err = input_register_device(hil_dev.dev);
|
err = input_register_device(hil_dev.dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
printk(KERN_ERR "HIL: Can't register device\n");
|
printk(KERN_ERR "HIL: Can't register device\n");
|
||||||
goto err3;
|
goto err2;
|
||||||
}
|
}
|
||||||
|
|
||||||
printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n",
|
printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n",
|
||||||
hil_dev.dev->name, kbid, HILBASE, HIL_IRQ);
|
hil_dev.dev->name, kbid, HILBASE, HIL_IRQ);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err3:
|
|
||||||
hil_do(HIL_INTOFF, NULL, 0);
|
|
||||||
disable_irq(HIL_IRQ);
|
|
||||||
free_irq(HIL_IRQ, hil_dev.dev_id);
|
|
||||||
err2:
|
err2:
|
||||||
#if defined(CONFIG_HP300)
|
hil_do(HIL_INTOFF, NULL, 0);
|
||||||
release_region(HILBASE + HIL_DATA, 2);
|
free_irq(HIL_IRQ, hil_dev.dev_id);
|
||||||
err1:
|
err1:
|
||||||
#endif
|
|
||||||
input_free_device(hil_dev.dev);
|
input_free_device(hil_dev.dev);
|
||||||
hil_dev.dev = NULL;
|
hil_dev.dev = NULL;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __devexit 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;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_PARISC)
|
#if defined(CONFIG_PARISC)
|
||||||
static int __init
|
static int __devinit hil_probe_chip(struct parisc_device *dev)
|
||||||
hil_init_chip(struct parisc_device *dev)
|
|
||||||
{
|
{
|
||||||
|
/* Only allow one HIL keyboard */
|
||||||
|
if (hil_dev.dev)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
if (!dev->irq) {
|
if (!dev->irq) {
|
||||||
printk(KERN_WARNING "HIL: IRQ not found for HIL bus at 0x%08lx\n", dev->hpa.start);
|
printk(KERN_WARNING "HIL: IRQ not found for HIL bus at 0x%p\n",
|
||||||
|
(void *)dev->hpa.start);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,51 +319,79 @@ hil_init_chip(struct parisc_device *dev)
|
||||||
return hil_keyb_init();
|
return hil_keyb_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __devexit hil_remove_chip(struct parisc_device *dev)
|
||||||
|
{
|
||||||
|
hil_keyb_exit();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct parisc_device_id hil_tbl[] = {
|
static struct parisc_device_id hil_tbl[] = {
|
||||||
{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00073 },
|
{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00073 },
|
||||||
{ 0, }
|
{ 0, }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Disabled to avoid conflicts with the HP SDC HIL drivers */
|
||||||
MODULE_DEVICE_TABLE(parisc, hil_tbl);
|
MODULE_DEVICE_TABLE(parisc, hil_tbl);
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct parisc_driver hil_driver = {
|
static struct parisc_driver hil_driver = {
|
||||||
.name = "hil",
|
.name = "hil",
|
||||||
.id_table = hil_tbl,
|
.id_table = hil_tbl,
|
||||||
.probe = hil_init_chip,
|
.probe = hil_probe_chip,
|
||||||
|
.remove = __devexit_p(hil_remove_chip),
|
||||||
};
|
};
|
||||||
#endif /* CONFIG_PARISC */
|
|
||||||
|
|
||||||
|
|
||||||
static int __init hil_init(void)
|
static int __init hil_init(void)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_PARISC)
|
|
||||||
return register_parisc_driver(&hil_driver);
|
return register_parisc_driver(&hil_driver);
|
||||||
#else
|
|
||||||
return hil_keyb_init();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void __exit hil_exit(void)
|
static void __exit hil_exit(void)
|
||||||
{
|
{
|
||||||
if (HIL_IRQ) {
|
unregister_parisc_driver(&hil_driver);
|
||||||
disable_irq(HIL_IRQ);
|
}
|
||||||
free_irq(HIL_IRQ, hil_dev.dev_id);
|
|
||||||
|
#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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Turn off interrupts */
|
if (!request_region(HILBASE + HIL_DATA, 2, "hil")) {
|
||||||
hil_do(HIL_INTOFF, NULL, 0);
|
printk(KERN_ERR "HIL: IOPORT region already used\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
input_unregister_device(hil_dev.dev);
|
error = hil_keyb_init();
|
||||||
|
if (error) {
|
||||||
|
release_region(HILBASE + HIL_DATA, 2);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
hil_dev.dev = NULL;
|
return 0;
|
||||||
|
|
||||||
#if defined(CONFIG_PARISC)
|
|
||||||
unregister_parisc_driver(&hil_driver);
|
|
||||||
#else
|
|
||||||
release_region(HILBASE+HIL_DATA, 2);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __exit hil_exit(void)
|
||||||
|
{
|
||||||
|
hil_keyb_exit();
|
||||||
|
release_region(HILBASE + HIL_DATA, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_PARISC */
|
||||||
|
|
||||||
module_init(hil_init);
|
module_init(hil_init);
|
||||||
module_exit(hil_exit);
|
module_exit(hil_exit);
|
||||||
|
|
Loading…
Reference in a new issue