Commit 6ab0f5cd authored by Matthew Wilcox's avatar Matthew Wilcox Committed by Kyle McMartin

[PARISC] Update parisc specific input code from parisc tree

Update drivers to new input layer changes.
Signed-off-by: default avatarHelge Deller <deller@parisc-linux.org>
Signed-off-by: default avatarMatthew Wilcox <willy@parisc-linux.org>

Reorder code in gscps2_interrupt() and only enable ports when opened.
This fixes issues with hangs booting an SMP kernel on my C360.
Previously serio_interrupt() could be called before the lock in
struct serio was initialised.
Signed-off-by: default avatarRichard Hirst <rhirst@parisc-linux.org>
Signed-off-by: default avatarKyle McMartin <kyle@parisc-linux.org>
parent ae8c75c1
...@@ -204,7 +204,7 @@ static irqreturn_t hil_kbd_interrupt(struct serio *serio, ...@@ -204,7 +204,7 @@ static irqreturn_t hil_kbd_interrupt(struct serio *serio,
hil_packet packet; hil_packet packet;
int idx; int idx;
kbd = (struct hil_kbd *)serio->private; kbd = serio_get_drvdata(serio);
if (kbd == NULL) { if (kbd == NULL) {
BUG(); BUG();
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -234,7 +234,7 @@ static void hil_kbd_disconnect(struct serio *serio) ...@@ -234,7 +234,7 @@ static void hil_kbd_disconnect(struct serio *serio)
{ {
struct hil_kbd *kbd; struct hil_kbd *kbd;
kbd = (struct hil_kbd *)serio->private; kbd = serio_get_drvdata(serio);
if (kbd == NULL) { if (kbd == NULL) {
BUG(); BUG();
return; return;
...@@ -245,20 +245,20 @@ static void hil_kbd_disconnect(struct serio *serio) ...@@ -245,20 +245,20 @@ static void hil_kbd_disconnect(struct serio *serio)
kfree(kbd); kfree(kbd);
} }
static void hil_kbd_connect(struct serio *serio, struct serio_driver *drv) static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct hil_kbd *kbd; struct hil_kbd *kbd;
uint8_t did, *idd; uint8_t did, *idd;
int i; int i;
if (serio->type != (SERIO_HIL_MLC | SERIO_HIL)) return; kbd = kmalloc(sizeof(*kbd), GFP_KERNEL);
if (!kbd)
if (!(kbd = kmalloc(sizeof(struct hil_kbd), GFP_KERNEL))) return; return -ENOMEM;
memset(kbd, 0, sizeof(struct hil_kbd)); memset(kbd, 0, sizeof(struct hil_kbd));
if (serio_open(serio, drv)) goto bail0; if (serio_open(serio, drv)) goto bail0;
serio->private = kbd; serio_set_drvdata(serio, kbd);
kbd->serio = serio; kbd->serio = serio;
kbd->dev.private = kbd; kbd->dev.private = kbd;
...@@ -342,19 +342,31 @@ static void hil_kbd_connect(struct serio *serio, struct serio_driver *drv) ...@@ -342,19 +342,31 @@ static void hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
down(&(kbd->sem)); down(&(kbd->sem));
up(&(kbd->sem)); up(&(kbd->sem));
return; return 0;
bail1: bail1:
serio_close(serio); serio_close(serio);
bail0: bail0:
kfree(kbd); kfree(kbd);
serio_set_drvdata(serio, NULL);
return -EIO;
} }
static struct serio_device_id hil_kbd_ids[] = {
{
.type = SERIO_HIL_MLC,
.proto = SERIO_HIL,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
struct serio_driver hil_kbd_serio_drv = { struct serio_driver hil_kbd_serio_drv = {
.driver = { .driver = {
.name = "hil_kbd", .name = "hil_kbd",
}, },
.description = "HP HIL keyboard driver", .description = "HP HIL keyboard driver",
.id_table = hil_kbd_ids,
.connect = hil_kbd_connect, .connect = hil_kbd_connect,
.disconnect = hil_kbd_disconnect, .disconnect = hil_kbd_disconnect,
.interrupt = hil_kbd_interrupt .interrupt = hil_kbd_interrupt
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/irq.h> #include <linux/interrupt.h>
#include <linux/hil.h> #include <linux/hil.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
......
...@@ -196,7 +196,7 @@ static irqreturn_t hil_ptr_interrupt(struct serio *serio, ...@@ -196,7 +196,7 @@ static irqreturn_t hil_ptr_interrupt(struct serio *serio,
hil_packet packet; hil_packet packet;
int idx; int idx;
ptr = (struct hil_ptr *)serio->private; ptr = serio_get_drvdata(serio);
if (ptr == NULL) { if (ptr == NULL) {
BUG(); BUG();
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -227,7 +227,7 @@ static void hil_ptr_disconnect(struct serio *serio) ...@@ -227,7 +227,7 @@ static void hil_ptr_disconnect(struct serio *serio)
{ {
struct hil_ptr *ptr; struct hil_ptr *ptr;
ptr = (struct hil_ptr *)serio->private; ptr = serio_get_drvdata(serio);
if (ptr == NULL) { if (ptr == NULL) {
BUG(); BUG();
return; return;
...@@ -238,21 +238,19 @@ static void hil_ptr_disconnect(struct serio *serio) ...@@ -238,21 +238,19 @@ static void hil_ptr_disconnect(struct serio *serio)
kfree(ptr); kfree(ptr);
} }
static void hil_ptr_connect(struct serio *serio, struct serio_driver *driver) static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
{ {
struct hil_ptr *ptr; struct hil_ptr *ptr;
char *txt; char *txt;
unsigned int i, naxsets, btntype; unsigned int i, naxsets, btntype;
uint8_t did, *idd; uint8_t did, *idd;
if (serio->type != (SERIO_HIL_MLC | SERIO_HIL)) return; if (!(ptr = kmalloc(sizeof(struct hil_ptr), GFP_KERNEL))) return -ENOMEM;
if (!(ptr = kmalloc(sizeof(struct hil_ptr), GFP_KERNEL))) return;
memset(ptr, 0, sizeof(struct hil_ptr)); memset(ptr, 0, sizeof(struct hil_ptr));
if (serio_open(serio, driver)) goto bail0; if (serio_open(serio, driver)) goto bail0;
serio->private = ptr; serio_set_drvdata(serio, ptr);
ptr->serio = serio; ptr->serio = serio;
ptr->dev.private = ptr; ptr->dev.private = ptr;
...@@ -380,23 +378,34 @@ static void hil_ptr_connect(struct serio *serio, struct serio_driver *driver) ...@@ -380,23 +378,34 @@ static void hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
(btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad", (btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad",
did); did);
return; return 0;
bail1: bail1:
serio_close(serio); serio_close(serio);
bail0: bail0:
kfree(ptr); kfree(ptr);
return; serio_set_drvdata(serio, NULL);
return -ENODEV;
} }
static struct serio_device_id hil_ptr_ids[] = {
{
.type = SERIO_HIL_MLC,
.proto = SERIO_HIL,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
static struct serio_driver hil_ptr_serio_driver = { static struct serio_driver hil_ptr_serio_driver = {
.driver = { .driver = {
.name = "hil_ptr", .name = "hil_ptr",
}, },
.description = "HP HIL mouse/tablet driver", .description = "HP HIL mouse/tablet driver",
.connect = hil_ptr_connect, .id_table = hil_ptr_ids,
.disconnect = hil_ptr_disconnect, .connect = hil_ptr_connect,
.interrupt = hil_ptr_interrupt .disconnect = hil_ptr_disconnect,
.interrupt = hil_ptr_interrupt
}; };
static int __init hil_ptr_init(void) static int __init hil_ptr_init(void)
......
...@@ -211,9 +211,6 @@ static void gscps2_reset(struct gscps2port *ps2port) ...@@ -211,9 +211,6 @@ static void gscps2_reset(struct gscps2port *ps2port)
writeb(0xff, addr+GSC_RESET); writeb(0xff, addr+GSC_RESET);
gscps2_flush(ps2port); gscps2_flush(ps2port);
spin_unlock_irqrestore(&ps2port->lock, flags); spin_unlock_irqrestore(&ps2port->lock, flags);
/* enable it */
gscps2_enable(ps2port, ENABLE);
} }
static LIST_HEAD(ps2port_list); static LIST_HEAD(ps2port_list);
...@@ -307,6 +304,9 @@ static int gscps2_open(struct serio *port) ...@@ -307,6 +304,9 @@ static int gscps2_open(struct serio *port)
gscps2_reset(ps2port); gscps2_reset(ps2port);
/* enable it */
gscps2_enable(ps2port, ENABLE);
gscps2_interrupt(0, NULL, NULL); gscps2_interrupt(0, NULL, NULL);
return 0; return 0;
...@@ -370,8 +370,6 @@ static int __init gscps2_probe(struct parisc_device *dev) ...@@ -370,8 +370,6 @@ static int __init gscps2_probe(struct parisc_device *dev)
serio->port_data = ps2port; serio->port_data = ps2port;
serio->dev.parent = &dev->dev; serio->dev.parent = &dev->dev;
list_add_tail(&ps2port->node, &ps2port_list);
ret = -EBUSY; ret = -EBUSY;
if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->port->name, ps2port)) if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->port->name, ps2port))
goto fail_miserably; goto fail_miserably;
...@@ -396,15 +394,16 @@ static int __init gscps2_probe(struct parisc_device *dev) ...@@ -396,15 +394,16 @@ static int __init gscps2_probe(struct parisc_device *dev)
serio_register_port(ps2port->port); serio_register_port(ps2port->port);
list_add_tail(&ps2port->node, &ps2port_list);
return 0; return 0;
fail: fail:
free_irq(dev->irq, ps2port); free_irq(dev->irq, ps2port);
fail_miserably: fail_miserably:
list_del(&ps2port->node);
iounmap(ps2port->addr); iounmap(ps2port->addr);
release_mem_region(dev->hpa, GSC_STATUS + 4); release_mem_region(dev->hpa.start, GSC_STATUS + 4);
fail_nomem: fail_nomem:
kfree(ps2port); kfree(ps2port);
......
...@@ -801,7 +801,8 @@ static int hil_mlc_serio_open(struct serio *serio) { ...@@ -801,7 +801,8 @@ static int hil_mlc_serio_open(struct serio *serio) {
struct hil_mlc_serio_map *map; struct hil_mlc_serio_map *map;
struct hil_mlc *mlc; struct hil_mlc *mlc;
if (serio->private != NULL) return -EBUSY; if (serio_get_drvdata(serio) != NULL)
return -EBUSY;
map = serio->port_data; map = serio->port_data;
if (map == NULL) { if (map == NULL) {
...@@ -832,11 +833,18 @@ static void hil_mlc_serio_close(struct serio *serio) { ...@@ -832,11 +833,18 @@ static void hil_mlc_serio_close(struct serio *serio) {
return; return;
} }
serio->private = NULL; serio_set_drvdata(serio, NULL);
serio->drv = NULL; serio->drv = NULL;
/* TODO wake up interruptable */ /* TODO wake up interruptable */
} }
static struct serio_device_id hil_mlc_serio_id = {
.type = SERIO_HIL_MLC,
.proto = SERIO_HIL,
.extra = SERIO_ANY,
.id = SERIO_ANY,
};
int hil_mlc_register(hil_mlc *mlc) { int hil_mlc_register(hil_mlc *mlc) {
int i; int i;
unsigned long flags; unsigned long flags;
...@@ -867,7 +875,7 @@ int hil_mlc_register(hil_mlc *mlc) { ...@@ -867,7 +875,7 @@ int hil_mlc_register(hil_mlc *mlc) {
mlc_serio = kmalloc(sizeof(*mlc_serio), GFP_KERNEL); mlc_serio = kmalloc(sizeof(*mlc_serio), GFP_KERNEL);
mlc->serio[i] = mlc_serio; mlc->serio[i] = mlc_serio;
memset(mlc_serio, 0, sizeof(*mlc_serio)); memset(mlc_serio, 0, sizeof(*mlc_serio));
mlc_serio->type = SERIO_HIL | SERIO_HIL_MLC; mlc_serio->id = hil_mlc_serio_id;
mlc_serio->write = hil_mlc_serio_write; mlc_serio->write = hil_mlc_serio_write;
mlc_serio->open = hil_mlc_serio_open; mlc_serio->open = hil_mlc_serio_open;
mlc_serio->close = hil_mlc_serio_close; mlc_serio->close = hil_mlc_serio_close;
......
This diff is collapsed.
/*
* HP Human Interface Loop Master Link Controller driver.
*
* Copyright (c) 2001 Brian S. Julin
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
*
* References:
* HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A
*
*/
#include <linux/hil.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <asm/semaphore.h>
#include <linux/serio.h>
#include <linux/list.h>
typedef struct hil_mlc hil_mlc;
/* The HIL has a complicated state engine.
* We define the structure of nodes in the state engine here.
*/
enum hilse_act {
/* HILSE_OUT prepares to receive input if the next node
* is an IN or EXPECT, and then sends the given packet.
*/
HILSE_OUT = 0,
/* HILSE_CTS checks if the loop is busy. */
HILSE_CTS,
/* HILSE_OUT_LAST sends the given command packet to
* the last configured/running device on the loop.
*/
HILSE_OUT_LAST,
/* HILSE_OUT_DISC sends the given command packet to
* the next device past the last configured/running one.
*/
HILSE_OUT_DISC,
/* HILSE_FUNC runs a callback function with given arguments.
* a positive return value causes the "ugly" branch to be taken.
*/
HILSE_FUNC,
/* HILSE_IN simply expects any non-errored packet to arrive
* within arg usecs.
*/
HILSE_IN = 0x100,
/* HILSE_EXPECT expects a particular packet to arrive
* within arg usecs, any other packet is considered an error.
*/
HILSE_EXPECT,
/* HILSE_EXPECT_LAST as above but dev field should be last
* discovered/operational device.
*/
HILSE_EXPECT_LAST,
/* HILSE_EXPECT_LAST as above but dev field should be first
* undiscovered/inoperational device.
*/
HILSE_EXPECT_DISC
};
typedef int (hilse_func) (hil_mlc *mlc, int arg);
struct hilse_node {
enum hilse_act act; /* How to process this node */
union {
hilse_func *func; /* Function to call if HILSE_FUNC */
hil_packet packet; /* Packet to send or to compare */
} object;
int arg; /* Timeout in usec or parm for func */
int good; /* Node to jump to on success */
int bad; /* Node to jump to on error */
int ugly; /* Node to jump to on timeout */
};
/* Methods for back-end drivers, e.g. hp_sdc_mlc */
typedef int (hil_mlc_cts) (hil_mlc *mlc);
typedef void (hil_mlc_out) (hil_mlc *mlc);
typedef int (hil_mlc_in) (hil_mlc *mlc, suseconds_t timeout);
struct hil_mlc_devinfo {
uint8_t idd[16]; /* Device ID Byte and Describe Record */
uint8_t rsc[16]; /* Security Code Header and Record */
uint8_t exd[16]; /* Extended Describe Record */
uint8_t rnm[16]; /* Device name as returned by RNM command */
};
struct hil_mlc_serio_map {
hil_mlc *mlc;
int di_revmap;
int didx;
};
/* How many (possibly old/detached) devices the we try to keep track of */
#define HIL_MLC_DEVMEM 16
struct hil_mlc {
struct list_head list; /* hil_mlc is organized as linked list */
rwlock_t lock;
void *priv; /* Data specific to a particular type of MLC */
int seidx; /* Current node in state engine */
int istarted, ostarted;
hil_mlc_cts *cts;
struct semaphore csem; /* Raised when loop idle */
hil_mlc_out *out;
struct semaphore osem; /* Raised when outpacket dispatched */
hil_packet opacket;
hil_mlc_in *in;
struct semaphore isem; /* Raised when a packet arrives */
hil_packet ipacket[16];
hil_packet imatch;
int icount;
struct timeval instart;
suseconds_t intimeout;
int ddi; /* Last operational device id */
int lcv; /* LCV to throttle loops */
struct timeval lcv_tv; /* Time loop was started */
int di_map[7]; /* Maps below items to live devs */
struct hil_mlc_devinfo di[HIL_MLC_DEVMEM];
struct serio *serio[HIL_MLC_DEVMEM];
struct hil_mlc_serio_map serio_map[HIL_MLC_DEVMEM];
hil_packet serio_opacket[HIL_MLC_DEVMEM];
int serio_oidx[HIL_MLC_DEVMEM];
struct hil_mlc_devinfo di_scratch; /* Temporary area */
int opercnt;
struct tasklet_struct *tasklet;
};
int hil_mlc_register(hil_mlc *mlc);
int hil_mlc_unregister(hil_mlc *mlc);
This diff is collapsed.
...@@ -644,6 +644,7 @@ struct input_absinfo { ...@@ -644,6 +644,7 @@ struct input_absinfo {
#define BUS_ADB 0x17 #define BUS_ADB 0x17
#define BUS_I2C 0x18 #define BUS_I2C 0x18
#define BUS_HOST 0x19 #define BUS_HOST 0x19
#define BUS_GSC 0x1A
/* /*
* Values describing the status of an effect * Values describing the status of an effect
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment