Commit 476627b5 authored by Vojtech Pavlik's avatar Vojtech Pavlik

Move delayed rescanning of the ports to serio.c, add a kernel thread

for that, so that hotplug events happen in process context.
parent eb9c08b3
......@@ -121,7 +121,6 @@ struct atkbd {
struct serio *serio;
char name[64];
char phys[32];
struct tq_struct tq;
unsigned char cmdbuf[4];
unsigned char cmdcnt;
unsigned char set;
......@@ -161,8 +160,7 @@ static void atkbd_interrupt(struct serio *serio, unsigned char data, unsigned in
switch (atkbd->keycode[code]) {
case ATKBD_KEY_BAT:
queue_task(&atkbd->tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
serio_rescan(atkbd->serio);
return;
case ATKBD_KEY_EMUL0:
atkbd->emul = 1;
......@@ -430,21 +428,6 @@ static void atkbd_disconnect(struct serio *serio)
kfree(atkbd);
}
/*
* atkbd_powerup() is called when the keyboard sends the 0xaa character,
* meaning that it was disconnected and reconnected. We close the port
* in that case and let the upper layer find an appropriate driver for
* the device that was connected. It may be a mouse, or a keyboard, we
* don't know yet.
*/
static void atkbd_powerup(void *data)
{
struct atkbd *atkbd = data;
mdelay(40); /* FIXME!!! Wait some nicer way */
serio_rescan(atkbd->serio);
}
/*
* atkbd_connect() is called when the serio module finds and interface
* that isn't handled yet by an appropriate device driver. We check if
......@@ -476,9 +459,6 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
atkbd->dev.event = atkbd_event;
atkbd->dev.private = atkbd;
atkbd->tq.routine = atkbd_powerup;
atkbd->tq.data = atkbd;
serio->private = atkbd;
if (serio_open(serio, dev)) {
......
......@@ -216,8 +216,7 @@ static void psmouse_interrupt(struct serio *serio, unsigned char data, unsigned
}
if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
queue_task(&psmouse->tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
serio_rescan(serio);
return;
}
}
......@@ -557,22 +556,6 @@ static void psmouse_disconnect(struct serio *serio)
kfree(psmouse);
}
/*
* psmouse_powerup() is called when we get the powerup
* sequence - 0xaa [0x00], so that the mouse/kbd is re-probed.
*/
static void psmouse_powerup(void *data)
{
struct psmouse *psmouse = data;
if (psmouse->packet[0] == PSMOUSE_RET_BAT && (psmouse->pktcnt == 1 ||
(psmouse->pktcnt == 2 && psmouse->packet[1] == 0x00))) {
mdelay(40); /* FIXME!!! Wait some nicer way */
serio_rescan(psmouse->serio);
}
}
/*
* psmouse_connect() is a callback form the serio module when
* an unhandled serio port is found.
......@@ -596,8 +579,6 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
psmouse->serio = serio;
psmouse->dev.private = psmouse;
psmouse->tq.routine = psmouse_powerup;
psmouse->tq.data = psmouse;
serio->private = psmouse;
......
......@@ -32,6 +32,11 @@
#include <linux/module.h>
#include <linux/serio.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/suspend.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Serio abstraction core");
......@@ -47,6 +52,7 @@ EXPORT_SYMBOL(serio_rescan);
static struct serio *serio_list;
static struct serio_dev *serio_dev;
static int serio_pid;
static void serio_find_dev(struct serio *serio)
{
......@@ -59,11 +65,49 @@ static void serio_find_dev(struct serio *serio)
}
}
#define SERIO_RESCAN 1
static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
static DECLARE_COMPLETION(serio_exited);
void serio_handle_events(void)
{
struct serio *serio = serio_list;
while (serio) {
if (serio->event & SERIO_RESCAN) {
if (serio->dev && serio->dev->disconnect)
serio->dev->disconnect(serio);
serio_find_dev(serio);
}
serio->event = 0;
}
}
static int serio_thread(void *nothing)
{
lock_kernel();
daemonize();
strcpy(current->comm, "kseriod");
do {
serio_handle_events();
if (current->flags & PF_FREEZE)
refrigerator(PF_IOTHREAD);
wait_event_interruptible(serio_wait, 1);
} while (!signal_pending(current));
printk(KERN_DEBUG "serio: kseriod exiting");
unlock_kernel();
complete_and_exit(&serio_exited, 0);
}
void serio_rescan(struct serio *serio)
{
if (serio->dev && serio->dev->disconnect)
serio->dev->disconnect(serio);
serio_find_dev(serio);
serio->event |= SERIO_RESCAN;
wake_up(&serio_wait);
}
void serio_register_port(struct serio *serio)
......@@ -127,3 +171,29 @@ void serio_close(struct serio *serio)
serio->close(serio);
serio->dev = NULL;
}
int serio_init(void)
{
int pid;
pid = kernel_thread(serio_thread, NULL,
CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
if (!pid) {
printk(KERN_WARNING "serio: Failed to start kseriod\n");
return -1;
}
serio_pid = pid;
return 0;
}
void serio_exit(void)
{
kill_proc(serio_pid, SIGTERM, 1);
wait_for_completion(&serio_exited);
}
module_init(serio_init);
module_exit(serio_exit);
......@@ -50,6 +50,7 @@ struct serio {
unsigned short idversion;
unsigned long type;
unsigned long event;
int (*write)(struct serio *, unsigned char);
int (*open)(struct serio *);
......
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