blob: 8a426375fcb31489bf2b289bad61f2528e970057 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * The Serio abstraction module
3 *
4 * Copyright (c) 1999-2004 Vojtech Pavlik
5 * Copyright (c) 2004 Dmitry Torokhov
6 * Copyright (c) 2003 Daniele Bellucci
7 */
8
9/*
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 * Should you need to contact me, the author, you can do so either by
25 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
26 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
27 */
28
Dmitry Torokhovcac91692010-01-05 17:56:04 -080029#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
30
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/stddef.h>
32#include <linux/module.h>
33#include <linux/serio.h>
34#include <linux/errno.h>
35#include <linux/wait.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/slab.h>
Linus Torvalds3c803e82005-06-27 17:49:45 -070038#include <linux/kthread.h>
Arjan van de Venc4e32e92006-02-19 00:21:55 -050039#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
42MODULE_DESCRIPTION("Serio abstraction core");
43MODULE_LICENSE("GPL");
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045/*
Arjan van de Venc4e32e92006-02-19 00:21:55 -050046 * serio_mutex protects entire serio subsystem and is taken every time
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 * serio port or driver registrered or unregistered.
48 */
Arjan van de Venc4e32e92006-02-19 00:21:55 -050049static DEFINE_MUTEX(serio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51static LIST_HEAD(serio_list);
52
Russell King30226f82006-01-05 14:38:53 +000053static struct bus_type serio_bus;
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55static void serio_add_port(struct serio *serio);
Shaohua Li6aabcdf2008-07-03 10:45:38 -040056static int serio_reconnect_port(struct serio *serio);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057static void serio_disconnect_port(struct serio *serio);
Shaohua Li6aabcdf2008-07-03 10:45:38 -040058static void serio_reconnect_chain(struct serio *serio);
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -050059static void serio_attach_driver(struct serio_driver *drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Linus Torvalds3c803e82005-06-27 17:49:45 -070061static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
62{
63 int retval;
64
Arjan van de Venc4e32e92006-02-19 00:21:55 -050065 mutex_lock(&serio->drv_mutex);
Linus Torvalds3c803e82005-06-27 17:49:45 -070066 retval = drv->connect(serio, drv);
Arjan van de Venc4e32e92006-02-19 00:21:55 -050067 mutex_unlock(&serio->drv_mutex);
Linus Torvalds3c803e82005-06-27 17:49:45 -070068
69 return retval;
70}
71
72static int serio_reconnect_driver(struct serio *serio)
73{
74 int retval = -1;
75
Arjan van de Venc4e32e92006-02-19 00:21:55 -050076 mutex_lock(&serio->drv_mutex);
Linus Torvalds3c803e82005-06-27 17:49:45 -070077 if (serio->drv && serio->drv->reconnect)
78 retval = serio->drv->reconnect(serio);
Arjan van de Venc4e32e92006-02-19 00:21:55 -050079 mutex_unlock(&serio->drv_mutex);
Linus Torvalds3c803e82005-06-27 17:49:45 -070080
81 return retval;
82}
83
84static void serio_disconnect_driver(struct serio *serio)
85{
Arjan van de Venc4e32e92006-02-19 00:21:55 -050086 mutex_lock(&serio->drv_mutex);
Linus Torvalds3c803e82005-06-27 17:49:45 -070087 if (serio->drv)
88 serio->drv->disconnect(serio);
Arjan van de Venc4e32e92006-02-19 00:21:55 -050089 mutex_unlock(&serio->drv_mutex);
Linus Torvalds3c803e82005-06-27 17:49:45 -070090}
91
Linus Torvalds1da177e2005-04-16 15:20:36 -070092static int serio_match_port(const struct serio_device_id *ids, struct serio *serio)
93{
94 while (ids->type || ids->proto) {
95 if ((ids->type == SERIO_ANY || ids->type == serio->id.type) &&
96 (ids->proto == SERIO_ANY || ids->proto == serio->id.proto) &&
97 (ids->extra == SERIO_ANY || ids->extra == serio->id.extra) &&
98 (ids->id == SERIO_ANY || ids->id == serio->id.id))
99 return 1;
100 ids++;
101 }
102 return 0;
103}
104
105/*
106 * Basic serio -> driver core mappings
107 */
108
Dmitry Torokhov70f256f2007-04-10 00:40:27 -0400109static int serio_bind_driver(struct serio *serio, struct serio_driver *drv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110{
Dmitry Torokhov0a660452006-10-12 01:06:23 -0400111 int error;
112
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 if (serio_match_port(drv->id_table, serio)) {
Dmitry Torokhov70f256f2007-04-10 00:40:27 -0400114
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 serio->dev.driver = &drv->driver;
Linus Torvalds3c803e82005-06-27 17:49:45 -0700116 if (serio_connect_driver(serio, drv)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 serio->dev.driver = NULL;
Dmitry Torokhov70f256f2007-04-10 00:40:27 -0400118 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 }
Dmitry Torokhov70f256f2007-04-10 00:40:27 -0400120
Dmitry Torokhov0a660452006-10-12 01:06:23 -0400121 error = device_bind_driver(&serio->dev);
122 if (error) {
Dmitry Torokhovcac91692010-01-05 17:56:04 -0800123 dev_warn(&serio->dev,
124 "device_bind_driver() failed for %s (%s) and %s, error: %d\n",
125 serio->phys, serio->name,
126 drv->description, error);
Dmitry Torokhov0a660452006-10-12 01:06:23 -0400127 serio_disconnect_driver(serio);
128 serio->dev.driver = NULL;
Dmitry Torokhov70f256f2007-04-10 00:40:27 -0400129 return error;
Dmitry Torokhov0a660452006-10-12 01:06:23 -0400130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 }
Dmitry Torokhov70f256f2007-04-10 00:40:27 -0400132 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133}
134
135static void serio_find_driver(struct serio *serio)
136{
Randy Dunlap73b59a32006-07-19 01:14:55 -0400137 int error;
138
Randy Dunlap73b59a32006-07-19 01:14:55 -0400139 error = device_attach(&serio->dev);
140 if (error < 0)
Dmitry Torokhovcac91692010-01-05 17:56:04 -0800141 dev_warn(&serio->dev,
142 "device_attach() failed for %s (%s), error: %d\n",
143 serio->phys, serio->name, error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144}
145
146
147/*
148 * Serio event processing.
149 */
150
151enum serio_event_type {
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500152 SERIO_RESCAN_PORT,
153 SERIO_RECONNECT_PORT,
Shaohua Li6aabcdf2008-07-03 10:45:38 -0400154 SERIO_RECONNECT_CHAIN,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 SERIO_REGISTER_PORT,
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500156 SERIO_ATTACH_DRIVER,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157};
158
159struct serio_event {
160 enum serio_event_type type;
161 void *object;
162 struct module *owner;
163 struct list_head node;
164};
165
166static DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */
167static LIST_HEAD(serio_event_list);
168static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
Linus Torvalds3c803e82005-06-27 17:49:45 -0700169static struct task_struct *serio_task;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500171static int serio_queue_event(void *object, struct module *owner,
172 enum serio_event_type event_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173{
174 unsigned long flags;
175 struct serio_event *event;
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500176 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
178 spin_lock_irqsave(&serio_event_lock, flags);
179
180 /*
Linus Torvalds3c803e82005-06-27 17:49:45 -0700181 * Scan event list for the other events for the same serio port,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 * starting with the most recent one. If event is the same we
183 * do not need add new one. If event is of different type we
184 * need to add this event and should not look further because
185 * we need to preseve sequence of distinct events.
Linus Torvalds3c803e82005-06-27 17:49:45 -0700186 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 list_for_each_entry_reverse(event, &serio_event_list, node) {
188 if (event->object == object) {
189 if (event->type == event_type)
190 goto out;
191 break;
192 }
193 }
194
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500195 event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC);
196 if (!event) {
Dmitry Torokhovcac91692010-01-05 17:56:04 -0800197 pr_err("Not enough memory to queue event %d\n", event_type);
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500198 retval = -ENOMEM;
199 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 }
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500201
202 if (!try_module_get(owner)) {
Dmitry Torokhovcac91692010-01-05 17:56:04 -0800203 pr_warning("Can't get module reference, dropping event %d\n",
204 event_type);
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500205 kfree(event);
206 retval = -EINVAL;
207 goto out;
208 }
209
210 event->type = event_type;
211 event->object = object;
212 event->owner = owner;
213
214 list_add_tail(&event->node, &serio_event_list);
215 wake_up(&serio_wait);
216
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217out:
218 spin_unlock_irqrestore(&serio_event_lock, flags);
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500219 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220}
221
222static void serio_free_event(struct serio_event *event)
223{
224 module_put(event->owner);
225 kfree(event);
226}
227
228static void serio_remove_duplicate_events(struct serio_event *event)
229{
Dmitry Torokhov4516c812010-01-05 17:56:04 -0800230 struct serio_event *e, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 unsigned long flags;
232
233 spin_lock_irqsave(&serio_event_lock, flags);
234
Dmitry Torokhov4516c812010-01-05 17:56:04 -0800235 list_for_each_entry_safe(e, next, &serio_event_list, node) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 if (event->object == e->object) {
237 /*
238 * If this event is of different type we should not
239 * look further - we only suppress duplicate events
240 * that were sent back-to-back.
241 */
242 if (event->type != e->type)
243 break;
244
Dmitry Torokhov4516c812010-01-05 17:56:04 -0800245 list_del_init(&e->node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 serio_free_event(e);
247 }
248 }
249
250 spin_unlock_irqrestore(&serio_event_lock, flags);
251}
252
253
254static struct serio_event *serio_get_event(void)
255{
Dmitry Torokhov4516c812010-01-05 17:56:04 -0800256 struct serio_event *event = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 unsigned long flags;
258
259 spin_lock_irqsave(&serio_event_lock, flags);
260
Dmitry Torokhov4516c812010-01-05 17:56:04 -0800261 if (!list_empty(&serio_event_list)) {
262 event = list_first_entry(&serio_event_list,
263 struct serio_event, node);
264 list_del_init(&event->node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 }
266
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 spin_unlock_irqrestore(&serio_event_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 return event;
269}
270
Dmitry Torokhov9e50afd2005-11-20 00:56:43 -0500271static void serio_handle_event(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272{
273 struct serio_event *event;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
Arjan van de Venc4e32e92006-02-19 00:21:55 -0500275 mutex_lock(&serio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
Dmitry Torokhovea486e62009-12-24 21:40:43 -0800277 while ((event = serio_get_event())) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
279 switch (event->type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Dmitry Torokhovcac91692010-01-05 17:56:04 -0800281 case SERIO_REGISTER_PORT:
282 serio_add_port(event->object);
283 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
Dmitry Torokhovcac91692010-01-05 17:56:04 -0800285 case SERIO_RECONNECT_PORT:
286 serio_reconnect_port(event->object);
287 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
Dmitry Torokhovcac91692010-01-05 17:56:04 -0800289 case SERIO_RESCAN_PORT:
290 serio_disconnect_port(event->object);
291 serio_find_driver(event->object);
292 break;
Shaohua Li6aabcdf2008-07-03 10:45:38 -0400293
Dmitry Torokhovcac91692010-01-05 17:56:04 -0800294 case SERIO_RECONNECT_CHAIN:
295 serio_reconnect_chain(event->object);
296 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
Dmitry Torokhovcac91692010-01-05 17:56:04 -0800298 case SERIO_ATTACH_DRIVER:
299 serio_attach_driver(event->object);
300 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 }
302
303 serio_remove_duplicate_events(event);
304 serio_free_event(event);
305 }
306
Arjan van de Venc4e32e92006-02-19 00:21:55 -0500307 mutex_unlock(&serio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308}
309
310/*
Dmitry Torokhove8ef4342008-06-02 00:41:57 -0400311 * Remove all events that have been submitted for a given
312 * object, be it serio port or driver.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 */
Dmitry Torokhove8ef4342008-06-02 00:41:57 -0400314static void serio_remove_pending_events(void *object)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
Dmitry Torokhov4516c812010-01-05 17:56:04 -0800316 struct serio_event *event, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 unsigned long flags;
318
319 spin_lock_irqsave(&serio_event_lock, flags);
320
Dmitry Torokhov4516c812010-01-05 17:56:04 -0800321 list_for_each_entry_safe(event, next, &serio_event_list, node) {
Dmitry Torokhove8ef4342008-06-02 00:41:57 -0400322 if (event->object == object) {
Dmitry Torokhov4516c812010-01-05 17:56:04 -0800323 list_del_init(&event->node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 serio_free_event(event);
325 }
326 }
327
328 spin_unlock_irqrestore(&serio_event_lock, flags);
329}
330
331/*
332 * Destroy child serio port (if any) that has not been fully registered yet.
333 *
334 * Note that we rely on the fact that port can have only one child and therefore
335 * only one child registration request can be pending. Additionally, children
336 * are registered by driver's connect() handler so there can't be a grandchild
337 * pending registration together with a child.
338 */
339static struct serio *serio_get_pending_child(struct serio *parent)
340{
341 struct serio_event *event;
342 struct serio *serio, *child = NULL;
343 unsigned long flags;
344
345 spin_lock_irqsave(&serio_event_lock, flags);
346
347 list_for_each_entry(event, &serio_event_list, node) {
348 if (event->type == SERIO_REGISTER_PORT) {
349 serio = event->object;
350 if (serio->parent == parent) {
351 child = serio;
352 break;
353 }
354 }
355 }
356
357 spin_unlock_irqrestore(&serio_event_lock, flags);
358 return child;
359}
360
361static int serio_thread(void *nothing)
362{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 do {
Dmitry Torokhov9e50afd2005-11-20 00:56:43 -0500364 serio_handle_event();
Dmitry Torokhovea486e62009-12-24 21:40:43 -0800365 wait_event_interruptible(serio_wait,
Linus Torvalds3c803e82005-06-27 17:49:45 -0700366 kthread_should_stop() || !list_empty(&serio_event_list));
Linus Torvalds3c803e82005-06-27 17:49:45 -0700367 } while (!kthread_should_stop());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
Linus Torvalds3c803e82005-06-27 17:49:45 -0700369 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370}
371
372
373/*
374 * Serio port operations
375 */
376
Yani Ioannoue404e272005-05-17 06:42:58 -0400377static ssize_t serio_show_description(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378{
379 struct serio *serio = to_serio_port(dev);
380 return sprintf(buf, "%s\n", serio->name);
381}
382
Dmitry Torokhovae87dff2005-06-30 00:48:34 -0500383static ssize_t serio_show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
384{
385 struct serio *serio = to_serio_port(dev);
386
387 return sprintf(buf, "serio:ty%02Xpr%02Xid%02Xex%02X\n",
388 serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);
389}
390
Yani Ioannoue404e272005-05-17 06:42:58 -0400391static ssize_t serio_show_id_type(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392{
393 struct serio *serio = to_serio_port(dev);
394 return sprintf(buf, "%02x\n", serio->id.type);
395}
396
Yani Ioannoue404e272005-05-17 06:42:58 -0400397static ssize_t serio_show_id_proto(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398{
399 struct serio *serio = to_serio_port(dev);
400 return sprintf(buf, "%02x\n", serio->id.proto);
401}
402
Yani Ioannoue404e272005-05-17 06:42:58 -0400403static ssize_t serio_show_id_id(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404{
405 struct serio *serio = to_serio_port(dev);
406 return sprintf(buf, "%02x\n", serio->id.id);
407}
408
Yani Ioannoue404e272005-05-17 06:42:58 -0400409static ssize_t serio_show_id_extra(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410{
411 struct serio *serio = to_serio_port(dev);
412 return sprintf(buf, "%02x\n", serio->id.extra);
413}
414
Dmitry Torokhovbaae9562005-05-16 21:53:09 -0700415static DEVICE_ATTR(type, S_IRUGO, serio_show_id_type, NULL);
416static DEVICE_ATTR(proto, S_IRUGO, serio_show_id_proto, NULL);
417static DEVICE_ATTR(id, S_IRUGO, serio_show_id_id, NULL);
418static DEVICE_ATTR(extra, S_IRUGO, serio_show_id_extra, NULL);
419
420static struct attribute *serio_device_id_attrs[] = {
421 &dev_attr_type.attr,
422 &dev_attr_proto.attr,
423 &dev_attr_id.attr,
424 &dev_attr_extra.attr,
425 NULL
426};
427
428static struct attribute_group serio_id_attr_group = {
429 .name = "id",
430 .attrs = serio_device_id_attrs,
431};
432
Dmitry Torokhov386d8772010-01-05 17:56:03 -0800433static const struct attribute_group *serio_device_attr_groups[] = {
434 &serio_id_attr_group,
435 NULL
436};
437
Yani Ioannoue404e272005-05-17 06:42:58 -0400438static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{
440 struct serio *serio = to_serio_port(dev);
441 struct device_driver *drv;
Dmitry Torokhov70f256f2007-04-10 00:40:27 -0400442 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
Dmitry Torokhov70f256f2007-04-10 00:40:27 -0400444 error = mutex_lock_interruptible(&serio_mutex);
445 if (error)
446 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 if (!strncmp(buf, "none", count)) {
449 serio_disconnect_port(serio);
450 } else if (!strncmp(buf, "reconnect", count)) {
Shaohua Li6aabcdf2008-07-03 10:45:38 -0400451 serio_reconnect_chain(serio);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 } else if (!strncmp(buf, "rescan", count)) {
453 serio_disconnect_port(serio);
454 serio_find_driver(serio);
455 } else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
456 serio_disconnect_port(serio);
Dmitry Torokhov70f256f2007-04-10 00:40:27 -0400457 error = serio_bind_driver(serio, to_serio_driver(drv));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 put_driver(drv);
459 } else {
Dmitry Torokhov70f256f2007-04-10 00:40:27 -0400460 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 }
462
Arjan van de Venc4e32e92006-02-19 00:21:55 -0500463 mutex_unlock(&serio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
Dmitry Torokhov70f256f2007-04-10 00:40:27 -0400465 return error ? error : count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466}
467
Yani Ioannoue404e272005-05-17 06:42:58 -0400468static ssize_t serio_show_bind_mode(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469{
470 struct serio *serio = to_serio_port(dev);
471 return sprintf(buf, "%s\n", serio->manual_bind ? "manual" : "auto");
472}
473
Yani Ioannoue404e272005-05-17 06:42:58 -0400474static ssize_t serio_set_bind_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475{
476 struct serio *serio = to_serio_port(dev);
477 int retval;
478
479 retval = count;
480 if (!strncmp(buf, "manual", count)) {
Dmitry Torokhov7e044e02009-05-09 16:08:05 -0700481 serio->manual_bind = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 } else if (!strncmp(buf, "auto", count)) {
Dmitry Torokhov7e044e02009-05-09 16:08:05 -0700483 serio->manual_bind = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 } else {
485 retval = -EINVAL;
486 }
487
488 return retval;
489}
490
491static struct device_attribute serio_device_attrs[] = {
492 __ATTR(description, S_IRUGO, serio_show_description, NULL),
Dmitry Torokhovae87dff2005-06-30 00:48:34 -0500493 __ATTR(modalias, S_IRUGO, serio_show_modalias, NULL),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 __ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver),
495 __ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode),
496 __ATTR_NULL
497};
498
499
500static void serio_release_port(struct device *dev)
501{
502 struct serio *serio = to_serio_port(dev);
503
504 kfree(serio);
505 module_put(THIS_MODULE);
506}
507
508/*
509 * Prepare serio port for registration.
510 */
511static void serio_init_port(struct serio *serio)
512{
513 static atomic_t serio_no = ATOMIC_INIT(0);
514
515 __module_get(THIS_MODULE);
516
Randy Dunlap73b59a32006-07-19 01:14:55 -0400517 INIT_LIST_HEAD(&serio->node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 spin_lock_init(&serio->lock);
Arjan van de Venc4e32e92006-02-19 00:21:55 -0500519 mutex_init(&serio->drv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 device_initialize(&serio->dev);
Kay Sieversa6c24902008-10-30 00:07:50 -0400521 dev_set_name(&serio->dev, "serio%ld",
522 (long)atomic_inc_return(&serio_no) - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 serio->dev.bus = &serio_bus;
524 serio->dev.release = serio_release_port;
Dmitry Torokhov386d8772010-01-05 17:56:03 -0800525 serio->dev.groups = serio_device_attr_groups;
Jiri Kosina88aa0102006-10-11 01:45:31 -0400526 if (serio->parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 serio->dev.parent = &serio->parent->dev;
Jiri Kosina88aa0102006-10-11 01:45:31 -0400528 serio->depth = serio->parent->depth + 1;
529 } else
530 serio->depth = 0;
531 lockdep_set_subclass(&serio->lock, serio->depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532}
533
534/*
535 * Complete serio port registration.
536 * Driver core will attempt to find appropriate driver for the port.
537 */
538static void serio_add_port(struct serio *serio)
539{
Randy Dunlap73b59a32006-07-19 01:14:55 -0400540 int error;
541
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 if (serio->parent) {
543 serio_pause_rx(serio->parent);
544 serio->parent->child = serio;
545 serio_continue_rx(serio->parent);
546 }
547
548 list_add_tail(&serio->node, &serio_list);
Dmitry Torokhov386d8772010-01-05 17:56:03 -0800549
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 if (serio->start)
551 serio->start(serio);
Dmitry Torokhov386d8772010-01-05 17:56:03 -0800552
Randy Dunlap73b59a32006-07-19 01:14:55 -0400553 error = device_add(&serio->dev);
554 if (error)
Dmitry Torokhovcac91692010-01-05 17:56:04 -0800555 dev_err(&serio->dev,
556 "device_add() failed for %s (%s), error: %d\n",
Randy Dunlap73b59a32006-07-19 01:14:55 -0400557 serio->phys, serio->name, error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558}
559
560/*
561 * serio_destroy_port() completes deregistration process and removes
562 * port from the system
563 */
564static void serio_destroy_port(struct serio *serio)
565{
566 struct serio *child;
567
568 child = serio_get_pending_child(serio);
569 if (child) {
570 serio_remove_pending_events(child);
571 put_device(&child->dev);
572 }
573
574 if (serio->stop)
575 serio->stop(serio);
576
577 if (serio->parent) {
578 serio_pause_rx(serio->parent);
579 serio->parent->child = NULL;
580 serio_continue_rx(serio->parent);
581 serio->parent = NULL;
582 }
583
Dmitry Torokhovddf1ffb2010-01-05 17:56:04 -0800584 if (device_is_registered(&serio->dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 device_del(&serio->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
Randy Dunlap73b59a32006-07-19 01:14:55 -0400587 list_del_init(&serio->node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 serio_remove_pending_events(serio);
589 put_device(&serio->dev);
590}
591
592/*
Shaohua Li6aabcdf2008-07-03 10:45:38 -0400593 * Reconnect serio port (re-initialize attached device).
594 * If reconnect fails (old device is no longer attached or
595 * there was no device to begin with) we do full rescan in
596 * hope of finding a driver for the port.
597 */
598static int serio_reconnect_port(struct serio *serio)
599{
600 int error = serio_reconnect_driver(serio);
601
602 if (error) {
603 serio_disconnect_port(serio);
604 serio_find_driver(serio);
605 }
606
607 return error;
608}
609
610/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 * Reconnect serio port and all its children (re-initialize attached devices)
612 */
Shaohua Li6aabcdf2008-07-03 10:45:38 -0400613static void serio_reconnect_chain(struct serio *serio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614{
615 do {
Shaohua Li6aabcdf2008-07-03 10:45:38 -0400616 if (serio_reconnect_port(serio)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 /* Ok, old children are now gone, we are done */
618 break;
619 }
620 serio = serio->child;
621 } while (serio);
622}
623
624/*
625 * serio_disconnect_port() unbinds a port from its driver. As a side effect
626 * all child ports are unbound and destroyed.
627 */
628static void serio_disconnect_port(struct serio *serio)
629{
630 struct serio *s, *parent;
631
632 if (serio->child) {
633 /*
634 * Children ports should be disconnected and destroyed
635 * first, staring with the leaf one, since we don't want
636 * to do recursion
637 */
638 for (s = serio; s->child; s = s->child)
639 /* empty */;
640
641 do {
642 parent = s->parent;
643
Dmitry Torokhov70f256f2007-04-10 00:40:27 -0400644 device_release_driver(&s->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 serio_destroy_port(s);
646 } while ((s = parent) != serio);
647 }
648
649 /*
650 * Ok, no children left, now disconnect this port
651 */
Dmitry Torokhov70f256f2007-04-10 00:40:27 -0400652 device_release_driver(&serio->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653}
654
655void serio_rescan(struct serio *serio)
656{
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500657 serio_queue_event(serio, NULL, SERIO_RESCAN_PORT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658}
Dmitry Torokhov89b09b92009-04-17 20:12:34 -0700659EXPORT_SYMBOL(serio_rescan);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
661void serio_reconnect(struct serio *serio)
662{
Shaohua Li6aabcdf2008-07-03 10:45:38 -0400663 serio_queue_event(serio, NULL, SERIO_RECONNECT_CHAIN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664}
Dmitry Torokhov89b09b92009-04-17 20:12:34 -0700665EXPORT_SYMBOL(serio_reconnect);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
667/*
668 * Submits register request to kseriod for subsequent execution.
669 * Note that port registration is always asynchronous.
670 */
671void __serio_register_port(struct serio *serio, struct module *owner)
672{
673 serio_init_port(serio);
674 serio_queue_event(serio, owner, SERIO_REGISTER_PORT);
675}
Dmitry Torokhov89b09b92009-04-17 20:12:34 -0700676EXPORT_SYMBOL(__serio_register_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
678/*
679 * Synchronously unregisters serio port.
680 */
681void serio_unregister_port(struct serio *serio)
682{
Arjan van de Venc4e32e92006-02-19 00:21:55 -0500683 mutex_lock(&serio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 serio_disconnect_port(serio);
685 serio_destroy_port(serio);
Arjan van de Venc4e32e92006-02-19 00:21:55 -0500686 mutex_unlock(&serio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687}
Dmitry Torokhov89b09b92009-04-17 20:12:34 -0700688EXPORT_SYMBOL(serio_unregister_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
690/*
Linus Torvalds3c803e82005-06-27 17:49:45 -0700691 * Safely unregisters child port if one is present.
692 */
693void serio_unregister_child_port(struct serio *serio)
694{
Arjan van de Venc4e32e92006-02-19 00:21:55 -0500695 mutex_lock(&serio_mutex);
Linus Torvalds3c803e82005-06-27 17:49:45 -0700696 if (serio->child) {
697 serio_disconnect_port(serio->child);
698 serio_destroy_port(serio->child);
699 }
Arjan van de Venc4e32e92006-02-19 00:21:55 -0500700 mutex_unlock(&serio_mutex);
Linus Torvalds3c803e82005-06-27 17:49:45 -0700701}
Dmitry Torokhov89b09b92009-04-17 20:12:34 -0700702EXPORT_SYMBOL(serio_unregister_child_port);
Linus Torvalds3c803e82005-06-27 17:49:45 -0700703
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
705/*
706 * Serio driver operations
707 */
708
709static ssize_t serio_driver_show_description(struct device_driver *drv, char *buf)
710{
711 struct serio_driver *driver = to_serio_driver(drv);
712 return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)");
713}
714
715static ssize_t serio_driver_show_bind_mode(struct device_driver *drv, char *buf)
716{
717 struct serio_driver *serio_drv = to_serio_driver(drv);
718 return sprintf(buf, "%s\n", serio_drv->manual_bind ? "manual" : "auto");
719}
720
721static ssize_t serio_driver_set_bind_mode(struct device_driver *drv, const char *buf, size_t count)
722{
723 struct serio_driver *serio_drv = to_serio_driver(drv);
724 int retval;
725
726 retval = count;
727 if (!strncmp(buf, "manual", count)) {
Dmitry Torokhov7e044e02009-05-09 16:08:05 -0700728 serio_drv->manual_bind = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 } else if (!strncmp(buf, "auto", count)) {
Dmitry Torokhov7e044e02009-05-09 16:08:05 -0700730 serio_drv->manual_bind = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 } else {
732 retval = -EINVAL;
733 }
734
735 return retval;
736}
737
738
739static struct driver_attribute serio_driver_attrs[] = {
740 __ATTR(description, S_IRUGO, serio_driver_show_description, NULL),
741 __ATTR(bind_mode, S_IWUSR | S_IRUGO,
742 serio_driver_show_bind_mode, serio_driver_set_bind_mode),
743 __ATTR_NULL
744};
745
746static int serio_driver_probe(struct device *dev)
747{
748 struct serio *serio = to_serio_port(dev);
749 struct serio_driver *drv = to_serio_driver(dev->driver);
750
Linus Torvalds3c803e82005-06-27 17:49:45 -0700751 return serio_connect_driver(serio, drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752}
753
754static int serio_driver_remove(struct device *dev)
755{
756 struct serio *serio = to_serio_port(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
Linus Torvalds3c803e82005-06-27 17:49:45 -0700758 serio_disconnect_driver(serio);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 return 0;
760}
761
Dmitry Torokhov82dd9ef2007-02-18 01:40:30 -0500762static void serio_cleanup(struct serio *serio)
763{
Dmitry Torokhov33143ea2007-06-29 01:06:35 -0400764 mutex_lock(&serio->drv_mutex);
Dmitry Torokhov82dd9ef2007-02-18 01:40:30 -0500765 if (serio->drv && serio->drv->cleanup)
766 serio->drv->cleanup(serio);
Dmitry Torokhov33143ea2007-06-29 01:06:35 -0400767 mutex_unlock(&serio->drv_mutex);
Dmitry Torokhov82dd9ef2007-02-18 01:40:30 -0500768}
769
770static void serio_shutdown(struct device *dev)
771{
772 struct serio *serio = to_serio_port(dev);
773
774 serio_cleanup(serio);
775}
776
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500777static void serio_attach_driver(struct serio_driver *drv)
Randy Dunlap73b59a32006-07-19 01:14:55 -0400778{
779 int error;
780
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500781 error = driver_attach(&drv->driver);
Randy Dunlap73b59a32006-07-19 01:14:55 -0400782 if (error)
Dmitry Torokhovcac91692010-01-05 17:56:04 -0800783 pr_warning("driver_attach() failed for %s with error %d\n",
784 drv->driver.name, error);
Randy Dunlap73b59a32006-07-19 01:14:55 -0400785}
786
Greg Kroah-Hartman4b315622007-01-15 11:50:02 -0800787int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788{
Dmitry Torokhov7e044e02009-05-09 16:08:05 -0700789 bool manual_bind = drv->manual_bind;
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500790 int error;
791
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 drv->driver.bus = &serio_bus;
Greg Kroah-Hartman4b315622007-01-15 11:50:02 -0800793 drv->driver.owner = owner;
794 drv->driver.mod_name = mod_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500796 /*
797 * Temporarily disable automatic binding because probing
798 * takes long time and we are better off doing it in kseriod
799 */
Dmitry Torokhov7e044e02009-05-09 16:08:05 -0700800 drv->manual_bind = true;
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500801
802 error = driver_register(&drv->driver);
803 if (error) {
Dmitry Torokhovcac91692010-01-05 17:56:04 -0800804 pr_err("driver_register() failed for %s, error: %d\n",
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500805 drv->driver.name, error);
806 return error;
807 }
808
809 /*
810 * Restore original bind mode and let kseriod bind the
811 * driver to free ports
812 */
813 if (!manual_bind) {
Dmitry Torokhov7e044e02009-05-09 16:08:05 -0700814 drv->manual_bind = false;
Dmitry Torokhoved7b1f62006-11-23 23:34:49 -0500815 error = serio_queue_event(drv, NULL, SERIO_ATTACH_DRIVER);
816 if (error) {
817 driver_unregister(&drv->driver);
818 return error;
819 }
820 }
821
822 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823}
Dmitry Torokhov89b09b92009-04-17 20:12:34 -0700824EXPORT_SYMBOL(__serio_register_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
826void serio_unregister_driver(struct serio_driver *drv)
827{
828 struct serio *serio;
829
Arjan van de Venc4e32e92006-02-19 00:21:55 -0500830 mutex_lock(&serio_mutex);
Dmitry Torokhove8ef4342008-06-02 00:41:57 -0400831
Dmitry Torokhov7e044e02009-05-09 16:08:05 -0700832 drv->manual_bind = true; /* so serio_find_driver ignores it */
Dmitry Torokhove8ef4342008-06-02 00:41:57 -0400833 serio_remove_pending_events(drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
835start_over:
836 list_for_each_entry(serio, &serio_list, node) {
837 if (serio->drv == drv) {
838 serio_disconnect_port(serio);
839 serio_find_driver(serio);
840 /* we could've deleted some ports, restart */
841 goto start_over;
842 }
843 }
844
845 driver_unregister(&drv->driver);
Arjan van de Venc4e32e92006-02-19 00:21:55 -0500846 mutex_unlock(&serio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847}
Dmitry Torokhov89b09b92009-04-17 20:12:34 -0700848EXPORT_SYMBOL(serio_unregister_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
850static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
851{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 serio_pause_rx(serio);
853 serio->drv = drv;
854 serio_continue_rx(serio);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855}
856
857static int serio_bus_match(struct device *dev, struct device_driver *drv)
858{
859 struct serio *serio = to_serio_port(dev);
860 struct serio_driver *serio_drv = to_serio_driver(drv);
861
862 if (serio->manual_bind || serio_drv->manual_bind)
863 return 0;
864
865 return serio_match_port(serio_drv->id_table, serio);
866}
867
868#ifdef CONFIG_HOTPLUG
869
Kay Sievers312c0042005-11-16 09:00:00 +0100870#define SERIO_ADD_UEVENT_VAR(fmt, val...) \
Dmitry Torokhovae87dff2005-06-30 00:48:34 -0500871 do { \
Kay Sievers7eff2e72007-08-14 15:15:12 +0200872 int err = add_uevent_var(env, fmt, val); \
Dmitry Torokhovae87dff2005-06-30 00:48:34 -0500873 if (err) \
874 return err; \
875 } while (0)
876
Kay Sievers7eff2e72007-08-14 15:15:12 +0200877static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878{
879 struct serio *serio;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
881 if (!dev)
882 return -ENODEV;
883
884 serio = to_serio_port(dev);
885
Kay Sievers312c0042005-11-16 09:00:00 +0100886 SERIO_ADD_UEVENT_VAR("SERIO_TYPE=%02x", serio->id.type);
887 SERIO_ADD_UEVENT_VAR("SERIO_PROTO=%02x", serio->id.proto);
888 SERIO_ADD_UEVENT_VAR("SERIO_ID=%02x", serio->id.id);
889 SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra);
890 SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X",
Dmitry Torokhovae87dff2005-06-30 00:48:34 -0500891 serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892
893 return 0;
894}
Kay Sievers312c0042005-11-16 09:00:00 +0100895#undef SERIO_ADD_UEVENT_VAR
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
897#else
898
Kay Sievers7eff2e72007-08-14 15:15:12 +0200899static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900{
901 return -ENODEV;
902}
903
904#endif /* CONFIG_HOTPLUG */
905
Dmitry Torokhov82dd9ef2007-02-18 01:40:30 -0500906#ifdef CONFIG_PM
Dmitry Torokhov633aae22009-07-22 21:51:36 -0700907static int serio_suspend(struct device *dev)
Dmitry Torokhov82dd9ef2007-02-18 01:40:30 -0500908{
Dmitry Torokhov7e044e02009-05-09 16:08:05 -0700909 struct serio *serio = to_serio_port(dev);
Dmitry Torokhov82dd9ef2007-02-18 01:40:30 -0500910
Dmitry Torokhov633aae22009-07-22 21:51:36 -0700911 serio_cleanup(serio);
Dmitry Torokhov82dd9ef2007-02-18 01:40:30 -0500912
913 return 0;
914}
915
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916static int serio_resume(struct device *dev)
917{
Dmitry Torokhov7e044e02009-05-09 16:08:05 -0700918 struct serio *serio = to_serio_port(dev);
919
Shaohua Li6aabcdf2008-07-03 10:45:38 -0400920 /*
921 * Driver reconnect can take a while, so better let kseriod
922 * deal with it.
923 */
Dmitry Torokhov633aae22009-07-22 21:51:36 -0700924 serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
926 return 0;
927}
Dmitry Torokhov633aae22009-07-22 21:51:36 -0700928
929static const struct dev_pm_ops serio_pm_ops = {
930 .suspend = serio_suspend,
931 .resume = serio_resume,
932 .poweroff = serio_suspend,
933 .restore = serio_resume,
934};
Dmitry Torokhov82dd9ef2007-02-18 01:40:30 -0500935#endif /* CONFIG_PM */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Arjan van de Venc4e32e92006-02-19 00:21:55 -0500937/* called from serio_driver->connect/disconnect methods under serio_mutex */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938int serio_open(struct serio *serio, struct serio_driver *drv)
939{
940 serio_set_drv(serio, drv);
941
942 if (serio->open && serio->open(serio)) {
943 serio_set_drv(serio, NULL);
944 return -1;
945 }
946 return 0;
947}
Dmitry Torokhov89b09b92009-04-17 20:12:34 -0700948EXPORT_SYMBOL(serio_open);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
Arjan van de Venc4e32e92006-02-19 00:21:55 -0500950/* called from serio_driver->connect/disconnect methods under serio_mutex */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951void serio_close(struct serio *serio)
952{
953 if (serio->close)
954 serio->close(serio);
955
956 serio_set_drv(serio, NULL);
957}
Dmitry Torokhov89b09b92009-04-17 20:12:34 -0700958EXPORT_SYMBOL(serio_close);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
960irqreturn_t serio_interrupt(struct serio *serio,
David Howells7d12e782006-10-05 14:55:46 +0100961 unsigned char data, unsigned int dfl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
963 unsigned long flags;
964 irqreturn_t ret = IRQ_NONE;
965
966 spin_lock_irqsave(&serio->lock, flags);
967
968 if (likely(serio->drv)) {
David Howells7d12e782006-10-05 14:55:46 +0100969 ret = serio->drv->interrupt(serio, data, dfl);
Dmitry Torokhovddf1ffb2010-01-05 17:56:04 -0800970 } else if (!dfl && device_is_registered(&serio->dev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 serio_rescan(serio);
972 ret = IRQ_HANDLED;
973 }
974
975 spin_unlock_irqrestore(&serio->lock, flags);
976
977 return ret;
978}
Dmitry Torokhov89b09b92009-04-17 20:12:34 -0700979EXPORT_SYMBOL(serio_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
Marton Nemeth1ea2a692006-11-02 23:27:21 -0500981static struct bus_type serio_bus = {
982 .name = "serio",
983 .dev_attrs = serio_device_attrs,
984 .drv_attrs = serio_driver_attrs,
985 .match = serio_bus_match,
986 .uevent = serio_uevent,
987 .probe = serio_driver_probe,
988 .remove = serio_driver_remove,
Dmitry Torokhov82dd9ef2007-02-18 01:40:30 -0500989 .shutdown = serio_shutdown,
990#ifdef CONFIG_PM
Dmitry Torokhov633aae22009-07-22 21:51:36 -0700991 .pm = &serio_pm_ops,
Dmitry Torokhov82dd9ef2007-02-18 01:40:30 -0500992#endif
Marton Nemeth1ea2a692006-11-02 23:27:21 -0500993};
994
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995static int __init serio_init(void)
996{
Randy Dunlap73b59a32006-07-19 01:14:55 -0400997 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998
Randy Dunlap73b59a32006-07-19 01:14:55 -0400999 error = bus_register(&serio_bus);
1000 if (error) {
Dmitry Torokhovcac91692010-01-05 17:56:04 -08001001 pr_err("Failed to register serio bus, error: %d\n", error);
Randy Dunlap73b59a32006-07-19 01:14:55 -04001002 return error;
1003 }
1004
1005 serio_task = kthread_run(serio_thread, NULL, "kseriod");
1006 if (IS_ERR(serio_task)) {
1007 bus_unregister(&serio_bus);
1008 error = PTR_ERR(serio_task);
Dmitry Torokhovcac91692010-01-05 17:56:04 -08001009 pr_err("Failed to start kseriod, error: %d\n", error);
Randy Dunlap73b59a32006-07-19 01:14:55 -04001010 return error;
1011 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
1013 return 0;
1014}
1015
1016static void __exit serio_exit(void)
1017{
1018 bus_unregister(&serio_bus);
Linus Torvalds3c803e82005-06-27 17:49:45 -07001019 kthread_stop(serio_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020}
1021
Dmitry Torokhov51c38f92006-02-19 00:22:51 -05001022subsys_initcall(serio_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023module_exit(serio_exit);