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 { ...@@ -121,7 +121,6 @@ struct atkbd {
struct serio *serio; struct serio *serio;
char name[64]; char name[64];
char phys[32]; char phys[32];
struct tq_struct tq;
unsigned char cmdbuf[4]; unsigned char cmdbuf[4];
unsigned char cmdcnt; unsigned char cmdcnt;
unsigned char set; unsigned char set;
...@@ -161,8 +160,7 @@ static void atkbd_interrupt(struct serio *serio, unsigned char data, unsigned in ...@@ -161,8 +160,7 @@ static void atkbd_interrupt(struct serio *serio, unsigned char data, unsigned in
switch (atkbd->keycode[code]) { switch (atkbd->keycode[code]) {
case ATKBD_KEY_BAT: case ATKBD_KEY_BAT:
queue_task(&atkbd->tq, &tq_immediate); serio_rescan(atkbd->serio);
mark_bh(IMMEDIATE_BH);
return; return;
case ATKBD_KEY_EMUL0: case ATKBD_KEY_EMUL0:
atkbd->emul = 1; atkbd->emul = 1;
...@@ -430,21 +428,6 @@ static void atkbd_disconnect(struct serio *serio) ...@@ -430,21 +428,6 @@ static void atkbd_disconnect(struct serio *serio)
kfree(atkbd); 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 * atkbd_connect() is called when the serio module finds and interface
* that isn't handled yet by an appropriate device driver. We check if * 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) ...@@ -476,9 +459,6 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
atkbd->dev.event = atkbd_event; atkbd->dev.event = atkbd_event;
atkbd->dev.private = atkbd; atkbd->dev.private = atkbd;
atkbd->tq.routine = atkbd_powerup;
atkbd->tq.data = atkbd;
serio->private = atkbd; serio->private = atkbd;
if (serio_open(serio, dev)) { if (serio_open(serio, dev)) {
......
...@@ -216,8 +216,7 @@ static void psmouse_interrupt(struct serio *serio, unsigned char data, unsigned ...@@ -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) { if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
queue_task(&psmouse->tq, &tq_immediate); serio_rescan(serio);
mark_bh(IMMEDIATE_BH);
return; return;
} }
} }
...@@ -557,22 +556,6 @@ static void psmouse_disconnect(struct serio *serio) ...@@ -557,22 +556,6 @@ static void psmouse_disconnect(struct serio *serio)
kfree(psmouse); 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 * psmouse_connect() is a callback form the serio module when
* an unhandled serio port is found. * an unhandled serio port is found.
...@@ -596,8 +579,6 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) ...@@ -596,8 +579,6 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
psmouse->serio = serio; psmouse->serio = serio;
psmouse->dev.private = psmouse; psmouse->dev.private = psmouse;
psmouse->tq.routine = psmouse_powerup;
psmouse->tq.data = psmouse;
serio->private = psmouse; serio->private = psmouse;
......
...@@ -32,6 +32,11 @@ ...@@ -32,6 +32,11 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/errno.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_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Serio abstraction core"); MODULE_DESCRIPTION("Serio abstraction core");
...@@ -47,6 +52,7 @@ EXPORT_SYMBOL(serio_rescan); ...@@ -47,6 +52,7 @@ EXPORT_SYMBOL(serio_rescan);
static struct serio *serio_list; static struct serio *serio_list;
static struct serio_dev *serio_dev; static struct serio_dev *serio_dev;
static int serio_pid;
static void serio_find_dev(struct serio *serio) static void serio_find_dev(struct serio *serio)
{ {
...@@ -59,11 +65,49 @@ 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) void serio_rescan(struct serio *serio)
{ {
if (serio->dev && serio->dev->disconnect) serio->event |= SERIO_RESCAN;
serio->dev->disconnect(serio); wake_up(&serio_wait);
serio_find_dev(serio);
} }
void serio_register_port(struct serio *serio) void serio_register_port(struct serio *serio)
...@@ -127,3 +171,29 @@ void serio_close(struct serio *serio) ...@@ -127,3 +171,29 @@ void serio_close(struct serio *serio)
serio->close(serio); serio->close(serio);
serio->dev = NULL; 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 { ...@@ -50,6 +50,7 @@ struct serio {
unsigned short idversion; unsigned short idversion;
unsigned long type; unsigned long type;
unsigned long event;
int (*write)(struct serio *, unsigned char); int (*write)(struct serio *, unsigned char);
int (*open)(struct serio *); 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