aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/serio
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor_core@ameritech.net>2005-05-17 00:53:07 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-05-17 10:59:10 -0400
commit1ff2c873ca11f9e6abffb004b908756b27597672 (patch)
tree0c231057e7d947882fcb33b5fa277ba08423a70b /drivers/input/serio
parentf3a5c73d5ecb40909db662c4d2ace497b25c5940 (diff)
[PATCH] serport oops fix
serport - avoid calling serio_interrupt or serio_write_wakeup on unregistered port. Also fix memory leak which could happen if serport was left unused by moving serio allocation down to serport_ldisc_read. Signed-off-by: Dmitry Torokhov <dtor@mail.ru> Cc: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/input/serio')
-rw-r--r--drivers/input/serio/serport.c98
1 files changed, 68 insertions, 30 deletions
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index 22f73683952b..f6b85222ba3d 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -27,11 +27,15 @@ MODULE_LICENSE("GPL");
27MODULE_ALIAS_LDISC(N_MOUSE); 27MODULE_ALIAS_LDISC(N_MOUSE);
28 28
29#define SERPORT_BUSY 1 29#define SERPORT_BUSY 1
30#define SERPORT_ACTIVE 2
31#define SERPORT_DEAD 3
30 32
31struct serport { 33struct serport {
32 struct tty_struct *tty; 34 struct tty_struct *tty;
33 wait_queue_head_t wait; 35 wait_queue_head_t wait;
34 struct serio *serio; 36 struct serio *serio;
37 struct serio_device_id id;
38 spinlock_t lock;
35 unsigned long flags; 39 unsigned long flags;
36}; 40};
37 41
@@ -45,11 +49,29 @@ static int serport_serio_write(struct serio *serio, unsigned char data)
45 return -(serport->tty->driver->write(serport->tty, &data, 1) != 1); 49 return -(serport->tty->driver->write(serport->tty, &data, 1) != 1);
46} 50}
47 51
52static int serport_serio_open(struct serio *serio)
53{
54 struct serport *serport = serio->port_data;
55 unsigned long flags;
56
57 spin_lock_irqsave(&serport->lock, flags);
58 set_bit(SERPORT_ACTIVE, &serport->flags);
59 spin_unlock_irqrestore(&serport->lock, flags);
60
61 return 0;
62}
63
64
48static void serport_serio_close(struct serio *serio) 65static void serport_serio_close(struct serio *serio)
49{ 66{
50 struct serport *serport = serio->port_data; 67 struct serport *serport = serio->port_data;
68 unsigned long flags;
69
70 spin_lock_irqsave(&serport->lock, flags);
71 clear_bit(SERPORT_ACTIVE, &serport->flags);
72 set_bit(SERPORT_DEAD, &serport->flags);
73 spin_unlock_irqrestore(&serport->lock, flags);
51 74
52 serport->serio->id.type = 0;
53 wake_up_interruptible(&serport->wait); 75 wake_up_interruptible(&serport->wait);
54} 76}
55 77
@@ -61,36 +83,21 @@ static void serport_serio_close(struct serio *serio)
61static int serport_ldisc_open(struct tty_struct *tty) 83static int serport_ldisc_open(struct tty_struct *tty)
62{ 84{
63 struct serport *serport; 85 struct serport *serport;
64 struct serio *serio;
65 char name[64];
66 86
67 if (!capable(CAP_SYS_ADMIN)) 87 if (!capable(CAP_SYS_ADMIN))
68 return -EPERM; 88 return -EPERM;
69 89
70 serport = kmalloc(sizeof(struct serport), GFP_KERNEL); 90 serport = kcalloc(1, sizeof(struct serport), GFP_KERNEL);
71 serio = kmalloc(sizeof(struct serio), GFP_KERNEL); 91 if (!serport)
72 if (unlikely(!serport || !serio)) {
73 kfree(serport);
74 kfree(serio);
75 return -ENOMEM; 92 return -ENOMEM;
76 }
77 93
78 memset(serport, 0, sizeof(struct serport));
79 serport->serio = serio;
80 set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
81 serport->tty = tty; 94 serport->tty = tty;
82 tty->disc_data = serport; 95 spin_lock_init(&serport->lock);
83
84 memset(serio, 0, sizeof(struct serio));
85 strlcpy(serio->name, "Serial port", sizeof(serio->name));
86 snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name));
87 serio->id.type = SERIO_RS232;
88 serio->write = serport_serio_write;
89 serio->close = serport_serio_close;
90 serio->port_data = serport;
91
92 init_waitqueue_head(&serport->wait); 96 init_waitqueue_head(&serport->wait);
93 97
98 tty->disc_data = serport;
99 set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
100
94 return 0; 101 return 0;
95} 102}
96 103
@@ -100,7 +107,8 @@ static int serport_ldisc_open(struct tty_struct *tty)
100 107
101static void serport_ldisc_close(struct tty_struct *tty) 108static void serport_ldisc_close(struct tty_struct *tty)
102{ 109{
103 struct serport *serport = (struct serport*) tty->disc_data; 110 struct serport *serport = (struct serport *) tty->disc_data;
111
104 kfree(serport); 112 kfree(serport);
105} 113}
106 114
@@ -116,9 +124,19 @@ static void serport_ldisc_close(struct tty_struct *tty)
116static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) 124static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
117{ 125{
118 struct serport *serport = (struct serport*) tty->disc_data; 126 struct serport *serport = (struct serport*) tty->disc_data;
127 unsigned long flags;
119 int i; 128 int i;
129
130 spin_lock_irqsave(&serport->lock, flags);
131
132 if (!test_bit(SERPORT_ACTIVE, &serport->flags))
133 goto out;
134
120 for (i = 0; i < count; i++) 135 for (i = 0; i < count; i++)
121 serio_interrupt(serport->serio, cp[i], 0, NULL); 136 serio_interrupt(serport->serio, cp[i], 0, NULL);
137
138out:
139 spin_unlock_irqrestore(&serport->lock, flags);
122} 140}
123 141
124/* 142/*
@@ -141,16 +159,33 @@ static int serport_ldisc_room(struct tty_struct *tty)
141static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char __user * buf, size_t nr) 159static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char __user * buf, size_t nr)
142{ 160{
143 struct serport *serport = (struct serport*) tty->disc_data; 161 struct serport *serport = (struct serport*) tty->disc_data;
162 struct serio *serio;
144 char name[64]; 163 char name[64];
145 164
146 if (test_and_set_bit(SERPORT_BUSY, &serport->flags)) 165 if (test_and_set_bit(SERPORT_BUSY, &serport->flags))
147 return -EBUSY; 166 return -EBUSY;
148 167
168 serport->serio = serio = kcalloc(1, sizeof(struct serio), GFP_KERNEL);
169 if (!serio)
170 return -ENOMEM;
171
172 strlcpy(serio->name, "Serial port", sizeof(serio->name));
173 snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name));
174 serio->id = serport->id;
175 serio->id.type = SERIO_RS232;
176 serio->write = serport_serio_write;
177 serio->open = serport_serio_open;
178 serio->close = serport_serio_close;
179 serio->port_data = serport;
180
149 serio_register_port(serport->serio); 181 serio_register_port(serport->serio);
150 printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name)); 182 printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name));
151 wait_event_interruptible(serport->wait, !serport->serio->id.type); 183
184 wait_event_interruptible(serport->wait, test_bit(SERPORT_DEAD, &serport->flags));
152 serio_unregister_port(serport->serio); 185 serio_unregister_port(serport->serio);
186 serport->serio = NULL;
153 187
188 clear_bit(SERPORT_DEAD, &serport->flags);
154 clear_bit(SERPORT_BUSY, &serport->flags); 189 clear_bit(SERPORT_BUSY, &serport->flags);
155 190
156 return 0; 191 return 0;
@@ -163,16 +198,15 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u
163static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg) 198static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)
164{ 199{
165 struct serport *serport = (struct serport*) tty->disc_data; 200 struct serport *serport = (struct serport*) tty->disc_data;
166 struct serio *serio = serport->serio;
167 unsigned long type; 201 unsigned long type;
168 202
169 if (cmd == SPIOCSTYPE) { 203 if (cmd == SPIOCSTYPE) {
170 if (get_user(type, (unsigned long __user *) arg)) 204 if (get_user(type, (unsigned long __user *) arg))
171 return -EFAULT; 205 return -EFAULT;
172 206
173 serio->id.proto = type & 0x000000ff; 207 serport->id.proto = type & 0x000000ff;
174 serio->id.id = (type & 0x0000ff00) >> 8; 208 serport->id.id = (type & 0x0000ff00) >> 8;
175 serio->id.extra = (type & 0x00ff0000) >> 16; 209 serport->id.extra = (type & 0x00ff0000) >> 16;
176 210
177 return 0; 211 return 0;
178 } 212 }
@@ -182,9 +216,13 @@ static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsi
182 216
183static void serport_ldisc_write_wakeup(struct tty_struct * tty) 217static void serport_ldisc_write_wakeup(struct tty_struct * tty)
184{ 218{
185 struct serport *sp = (struct serport *) tty->disc_data; 219 struct serport *serport = (struct serport *) tty->disc_data;
220 unsigned long flags;
186 221
187 serio_drv_write_wakeup(sp->serio); 222 spin_lock_irqsave(&serport->lock, flags);
223 if (test_bit(SERPORT_ACTIVE, &serport->flags))
224 serio_drv_write_wakeup(serport->serio);
225 spin_unlock_irqrestore(&serport->lock, flags);
188} 226}
189 227
190/* 228/*