162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * The Serio abstraction module 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 1999-2004 Vojtech Pavlik 662306a36Sopenharmony_ci * Copyright (c) 2004 Dmitry Torokhov 762306a36Sopenharmony_ci * Copyright (c) 2003 Daniele Bellucci 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/stddef.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/serio.h> 1562306a36Sopenharmony_ci#include <linux/errno.h> 1662306a36Sopenharmony_ci#include <linux/sched.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/workqueue.h> 1962306a36Sopenharmony_ci#include <linux/mutex.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ciMODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 2262306a36Sopenharmony_ciMODULE_DESCRIPTION("Serio abstraction core"); 2362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* 2662306a36Sopenharmony_ci * serio_mutex protects entire serio subsystem and is taken every time 2762306a36Sopenharmony_ci * serio port or driver registered or unregistered. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_cistatic DEFINE_MUTEX(serio_mutex); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic LIST_HEAD(serio_list); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic void serio_add_port(struct serio *serio); 3462306a36Sopenharmony_cistatic int serio_reconnect_port(struct serio *serio); 3562306a36Sopenharmony_cistatic void serio_disconnect_port(struct serio *serio); 3662306a36Sopenharmony_cistatic void serio_reconnect_subtree(struct serio *serio); 3762306a36Sopenharmony_cistatic void serio_attach_driver(struct serio_driver *drv); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic int serio_connect_driver(struct serio *serio, struct serio_driver *drv) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci int retval; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci mutex_lock(&serio->drv_mutex); 4462306a36Sopenharmony_ci retval = drv->connect(serio, drv); 4562306a36Sopenharmony_ci mutex_unlock(&serio->drv_mutex); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci return retval; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic int serio_reconnect_driver(struct serio *serio) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci int retval = -1; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci mutex_lock(&serio->drv_mutex); 5562306a36Sopenharmony_ci if (serio->drv && serio->drv->reconnect) 5662306a36Sopenharmony_ci retval = serio->drv->reconnect(serio); 5762306a36Sopenharmony_ci mutex_unlock(&serio->drv_mutex); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci return retval; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic void serio_disconnect_driver(struct serio *serio) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci mutex_lock(&serio->drv_mutex); 6562306a36Sopenharmony_ci if (serio->drv) 6662306a36Sopenharmony_ci serio->drv->disconnect(serio); 6762306a36Sopenharmony_ci mutex_unlock(&serio->drv_mutex); 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic int serio_match_port(const struct serio_device_id *ids, struct serio *serio) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci while (ids->type || ids->proto) { 7362306a36Sopenharmony_ci if ((ids->type == SERIO_ANY || ids->type == serio->id.type) && 7462306a36Sopenharmony_ci (ids->proto == SERIO_ANY || ids->proto == serio->id.proto) && 7562306a36Sopenharmony_ci (ids->extra == SERIO_ANY || ids->extra == serio->id.extra) && 7662306a36Sopenharmony_ci (ids->id == SERIO_ANY || ids->id == serio->id.id)) 7762306a36Sopenharmony_ci return 1; 7862306a36Sopenharmony_ci ids++; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci return 0; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* 8462306a36Sopenharmony_ci * Basic serio -> driver core mappings 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic int serio_bind_driver(struct serio *serio, struct serio_driver *drv) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci int error; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (serio_match_port(drv->id_table, serio)) { 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci serio->dev.driver = &drv->driver; 9462306a36Sopenharmony_ci if (serio_connect_driver(serio, drv)) { 9562306a36Sopenharmony_ci serio->dev.driver = NULL; 9662306a36Sopenharmony_ci return -ENODEV; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci error = device_bind_driver(&serio->dev); 10062306a36Sopenharmony_ci if (error) { 10162306a36Sopenharmony_ci dev_warn(&serio->dev, 10262306a36Sopenharmony_ci "device_bind_driver() failed for %s (%s) and %s, error: %d\n", 10362306a36Sopenharmony_ci serio->phys, serio->name, 10462306a36Sopenharmony_ci drv->description, error); 10562306a36Sopenharmony_ci serio_disconnect_driver(serio); 10662306a36Sopenharmony_ci serio->dev.driver = NULL; 10762306a36Sopenharmony_ci return error; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci return 0; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic void serio_find_driver(struct serio *serio) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci int error; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci error = device_attach(&serio->dev); 11862306a36Sopenharmony_ci if (error < 0 && error != -EPROBE_DEFER) 11962306a36Sopenharmony_ci dev_warn(&serio->dev, 12062306a36Sopenharmony_ci "device_attach() failed for %s (%s), error: %d\n", 12162306a36Sopenharmony_ci serio->phys, serio->name, error); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/* 12662306a36Sopenharmony_ci * Serio event processing. 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cienum serio_event_type { 13062306a36Sopenharmony_ci SERIO_RESCAN_PORT, 13162306a36Sopenharmony_ci SERIO_RECONNECT_PORT, 13262306a36Sopenharmony_ci SERIO_RECONNECT_SUBTREE, 13362306a36Sopenharmony_ci SERIO_REGISTER_PORT, 13462306a36Sopenharmony_ci SERIO_ATTACH_DRIVER, 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistruct serio_event { 13862306a36Sopenharmony_ci enum serio_event_type type; 13962306a36Sopenharmony_ci void *object; 14062306a36Sopenharmony_ci struct module *owner; 14162306a36Sopenharmony_ci struct list_head node; 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */ 14562306a36Sopenharmony_cistatic LIST_HEAD(serio_event_list); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic struct serio_event *serio_get_event(void) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct serio_event *event = NULL; 15062306a36Sopenharmony_ci unsigned long flags; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci spin_lock_irqsave(&serio_event_lock, flags); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (!list_empty(&serio_event_list)) { 15562306a36Sopenharmony_ci event = list_first_entry(&serio_event_list, 15662306a36Sopenharmony_ci struct serio_event, node); 15762306a36Sopenharmony_ci list_del_init(&event->node); 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci spin_unlock_irqrestore(&serio_event_lock, flags); 16162306a36Sopenharmony_ci return event; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic void serio_free_event(struct serio_event *event) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci module_put(event->owner); 16762306a36Sopenharmony_ci kfree(event); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic void serio_remove_duplicate_events(void *object, 17162306a36Sopenharmony_ci enum serio_event_type type) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct serio_event *e, *next; 17462306a36Sopenharmony_ci unsigned long flags; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci spin_lock_irqsave(&serio_event_lock, flags); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci list_for_each_entry_safe(e, next, &serio_event_list, node) { 17962306a36Sopenharmony_ci if (object == e->object) { 18062306a36Sopenharmony_ci /* 18162306a36Sopenharmony_ci * If this event is of different type we should not 18262306a36Sopenharmony_ci * look further - we only suppress duplicate events 18362306a36Sopenharmony_ci * that were sent back-to-back. 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_ci if (type != e->type) 18662306a36Sopenharmony_ci break; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci list_del_init(&e->node); 18962306a36Sopenharmony_ci serio_free_event(e); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci spin_unlock_irqrestore(&serio_event_lock, flags); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic void serio_handle_event(struct work_struct *work) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci struct serio_event *event; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci mutex_lock(&serio_mutex); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci while ((event = serio_get_event())) { 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci switch (event->type) { 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci case SERIO_REGISTER_PORT: 20762306a36Sopenharmony_ci serio_add_port(event->object); 20862306a36Sopenharmony_ci break; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci case SERIO_RECONNECT_PORT: 21162306a36Sopenharmony_ci serio_reconnect_port(event->object); 21262306a36Sopenharmony_ci break; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci case SERIO_RESCAN_PORT: 21562306a36Sopenharmony_ci serio_disconnect_port(event->object); 21662306a36Sopenharmony_ci serio_find_driver(event->object); 21762306a36Sopenharmony_ci break; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci case SERIO_RECONNECT_SUBTREE: 22062306a36Sopenharmony_ci serio_reconnect_subtree(event->object); 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci case SERIO_ATTACH_DRIVER: 22462306a36Sopenharmony_ci serio_attach_driver(event->object); 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci serio_remove_duplicate_events(event->object, event->type); 22962306a36Sopenharmony_ci serio_free_event(event); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci mutex_unlock(&serio_mutex); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic DECLARE_WORK(serio_event_work, serio_handle_event); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic int serio_queue_event(void *object, struct module *owner, 23862306a36Sopenharmony_ci enum serio_event_type event_type) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci unsigned long flags; 24162306a36Sopenharmony_ci struct serio_event *event; 24262306a36Sopenharmony_ci int retval = 0; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci spin_lock_irqsave(&serio_event_lock, flags); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* 24762306a36Sopenharmony_ci * Scan event list for the other events for the same serio port, 24862306a36Sopenharmony_ci * starting with the most recent one. If event is the same we 24962306a36Sopenharmony_ci * do not need add new one. If event is of different type we 25062306a36Sopenharmony_ci * need to add this event and should not look further because 25162306a36Sopenharmony_ci * we need to preseve sequence of distinct events. 25262306a36Sopenharmony_ci */ 25362306a36Sopenharmony_ci list_for_each_entry_reverse(event, &serio_event_list, node) { 25462306a36Sopenharmony_ci if (event->object == object) { 25562306a36Sopenharmony_ci if (event->type == event_type) 25662306a36Sopenharmony_ci goto out; 25762306a36Sopenharmony_ci break; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC); 26262306a36Sopenharmony_ci if (!event) { 26362306a36Sopenharmony_ci pr_err("Not enough memory to queue event %d\n", event_type); 26462306a36Sopenharmony_ci retval = -ENOMEM; 26562306a36Sopenharmony_ci goto out; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (!try_module_get(owner)) { 26962306a36Sopenharmony_ci pr_warn("Can't get module reference, dropping event %d\n", 27062306a36Sopenharmony_ci event_type); 27162306a36Sopenharmony_ci kfree(event); 27262306a36Sopenharmony_ci retval = -EINVAL; 27362306a36Sopenharmony_ci goto out; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci event->type = event_type; 27762306a36Sopenharmony_ci event->object = object; 27862306a36Sopenharmony_ci event->owner = owner; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci list_add_tail(&event->node, &serio_event_list); 28162306a36Sopenharmony_ci queue_work(system_long_wq, &serio_event_work); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ciout: 28462306a36Sopenharmony_ci spin_unlock_irqrestore(&serio_event_lock, flags); 28562306a36Sopenharmony_ci return retval; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci/* 28962306a36Sopenharmony_ci * Remove all events that have been submitted for a given 29062306a36Sopenharmony_ci * object, be it serio port or driver. 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_cistatic void serio_remove_pending_events(void *object) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci struct serio_event *event, *next; 29562306a36Sopenharmony_ci unsigned long flags; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci spin_lock_irqsave(&serio_event_lock, flags); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci list_for_each_entry_safe(event, next, &serio_event_list, node) { 30062306a36Sopenharmony_ci if (event->object == object) { 30162306a36Sopenharmony_ci list_del_init(&event->node); 30262306a36Sopenharmony_ci serio_free_event(event); 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci spin_unlock_irqrestore(&serio_event_lock, flags); 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci/* 31062306a36Sopenharmony_ci * Locate child serio port (if any) that has not been fully registered yet. 31162306a36Sopenharmony_ci * 31262306a36Sopenharmony_ci * Children are registered by driver's connect() handler so there can't be a 31362306a36Sopenharmony_ci * grandchild pending registration together with a child. 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_cistatic struct serio *serio_get_pending_child(struct serio *parent) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct serio_event *event; 31862306a36Sopenharmony_ci struct serio *serio, *child = NULL; 31962306a36Sopenharmony_ci unsigned long flags; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci spin_lock_irqsave(&serio_event_lock, flags); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci list_for_each_entry(event, &serio_event_list, node) { 32462306a36Sopenharmony_ci if (event->type == SERIO_REGISTER_PORT) { 32562306a36Sopenharmony_ci serio = event->object; 32662306a36Sopenharmony_ci if (serio->parent == parent) { 32762306a36Sopenharmony_ci child = serio; 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci spin_unlock_irqrestore(&serio_event_lock, flags); 33462306a36Sopenharmony_ci return child; 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci/* 33862306a36Sopenharmony_ci * Serio port operations 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic ssize_t serio_show_description(struct device *dev, struct device_attribute *attr, char *buf) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 34462306a36Sopenharmony_ci return sprintf(buf, "%s\n", serio->name); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci return sprintf(buf, "serio:ty%02Xpr%02Xid%02Xex%02X\n", 35262306a36Sopenharmony_ci serio->id.type, serio->id.proto, serio->id.id, serio->id.extra); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 35862306a36Sopenharmony_ci return sprintf(buf, "%02x\n", serio->id.type); 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic ssize_t proto_show(struct device *dev, struct device_attribute *attr, char *buf) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 36462306a36Sopenharmony_ci return sprintf(buf, "%02x\n", serio->id.proto); 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 37062306a36Sopenharmony_ci return sprintf(buf, "%02x\n", serio->id.id); 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic ssize_t extra_show(struct device *dev, struct device_attribute *attr, char *buf) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 37662306a36Sopenharmony_ci return sprintf(buf, "%02x\n", serio->id.extra); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic ssize_t drvctl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 38262306a36Sopenharmony_ci struct device_driver *drv; 38362306a36Sopenharmony_ci int error; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci error = mutex_lock_interruptible(&serio_mutex); 38662306a36Sopenharmony_ci if (error) 38762306a36Sopenharmony_ci return error; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (!strncmp(buf, "none", count)) { 39062306a36Sopenharmony_ci serio_disconnect_port(serio); 39162306a36Sopenharmony_ci } else if (!strncmp(buf, "reconnect", count)) { 39262306a36Sopenharmony_ci serio_reconnect_subtree(serio); 39362306a36Sopenharmony_ci } else if (!strncmp(buf, "rescan", count)) { 39462306a36Sopenharmony_ci serio_disconnect_port(serio); 39562306a36Sopenharmony_ci serio_find_driver(serio); 39662306a36Sopenharmony_ci serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT); 39762306a36Sopenharmony_ci } else if ((drv = driver_find(buf, &serio_bus)) != NULL) { 39862306a36Sopenharmony_ci serio_disconnect_port(serio); 39962306a36Sopenharmony_ci error = serio_bind_driver(serio, to_serio_driver(drv)); 40062306a36Sopenharmony_ci serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT); 40162306a36Sopenharmony_ci } else { 40262306a36Sopenharmony_ci error = -EINVAL; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci mutex_unlock(&serio_mutex); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci return error ? error : count; 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic ssize_t serio_show_bind_mode(struct device *dev, struct device_attribute *attr, char *buf) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 41362306a36Sopenharmony_ci return sprintf(buf, "%s\n", serio->manual_bind ? "manual" : "auto"); 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic ssize_t serio_set_bind_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 41962306a36Sopenharmony_ci int retval; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci retval = count; 42262306a36Sopenharmony_ci if (!strncmp(buf, "manual", count)) { 42362306a36Sopenharmony_ci serio->manual_bind = true; 42462306a36Sopenharmony_ci } else if (!strncmp(buf, "auto", count)) { 42562306a36Sopenharmony_ci serio->manual_bind = false; 42662306a36Sopenharmony_ci } else { 42762306a36Sopenharmony_ci retval = -EINVAL; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci return retval; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic ssize_t firmware_id_show(struct device *dev, struct device_attribute *attr, char *buf) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci return sprintf(buf, "%s\n", serio->firmware_id); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(type); 44162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(proto); 44262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(id); 44362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(extra); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic struct attribute *serio_device_id_attrs[] = { 44662306a36Sopenharmony_ci &dev_attr_type.attr, 44762306a36Sopenharmony_ci &dev_attr_proto.attr, 44862306a36Sopenharmony_ci &dev_attr_id.attr, 44962306a36Sopenharmony_ci &dev_attr_extra.attr, 45062306a36Sopenharmony_ci NULL 45162306a36Sopenharmony_ci}; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic const struct attribute_group serio_id_attr_group = { 45462306a36Sopenharmony_ci .name = "id", 45562306a36Sopenharmony_ci .attrs = serio_device_id_attrs, 45662306a36Sopenharmony_ci}; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(modalias); 45962306a36Sopenharmony_cistatic DEVICE_ATTR_WO(drvctl); 46062306a36Sopenharmony_cistatic DEVICE_ATTR(description, S_IRUGO, serio_show_description, NULL); 46162306a36Sopenharmony_cistatic DEVICE_ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode); 46262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(firmware_id); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic struct attribute *serio_device_attrs[] = { 46562306a36Sopenharmony_ci &dev_attr_modalias.attr, 46662306a36Sopenharmony_ci &dev_attr_description.attr, 46762306a36Sopenharmony_ci &dev_attr_drvctl.attr, 46862306a36Sopenharmony_ci &dev_attr_bind_mode.attr, 46962306a36Sopenharmony_ci &dev_attr_firmware_id.attr, 47062306a36Sopenharmony_ci NULL 47162306a36Sopenharmony_ci}; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic const struct attribute_group serio_device_attr_group = { 47462306a36Sopenharmony_ci .attrs = serio_device_attrs, 47562306a36Sopenharmony_ci}; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic const struct attribute_group *serio_device_attr_groups[] = { 47862306a36Sopenharmony_ci &serio_id_attr_group, 47962306a36Sopenharmony_ci &serio_device_attr_group, 48062306a36Sopenharmony_ci NULL 48162306a36Sopenharmony_ci}; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic void serio_release_port(struct device *dev) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci kfree(serio); 48862306a36Sopenharmony_ci module_put(THIS_MODULE); 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci/* 49262306a36Sopenharmony_ci * Prepare serio port for registration. 49362306a36Sopenharmony_ci */ 49462306a36Sopenharmony_cistatic void serio_init_port(struct serio *serio) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci static atomic_t serio_no = ATOMIC_INIT(-1); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci __module_get(THIS_MODULE); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci INIT_LIST_HEAD(&serio->node); 50162306a36Sopenharmony_ci INIT_LIST_HEAD(&serio->child_node); 50262306a36Sopenharmony_ci INIT_LIST_HEAD(&serio->children); 50362306a36Sopenharmony_ci spin_lock_init(&serio->lock); 50462306a36Sopenharmony_ci mutex_init(&serio->drv_mutex); 50562306a36Sopenharmony_ci device_initialize(&serio->dev); 50662306a36Sopenharmony_ci dev_set_name(&serio->dev, "serio%lu", 50762306a36Sopenharmony_ci (unsigned long)atomic_inc_return(&serio_no)); 50862306a36Sopenharmony_ci serio->dev.bus = &serio_bus; 50962306a36Sopenharmony_ci serio->dev.release = serio_release_port; 51062306a36Sopenharmony_ci serio->dev.groups = serio_device_attr_groups; 51162306a36Sopenharmony_ci if (serio->parent) { 51262306a36Sopenharmony_ci serio->dev.parent = &serio->parent->dev; 51362306a36Sopenharmony_ci serio->depth = serio->parent->depth + 1; 51462306a36Sopenharmony_ci } else 51562306a36Sopenharmony_ci serio->depth = 0; 51662306a36Sopenharmony_ci lockdep_set_subclass(&serio->lock, serio->depth); 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci/* 52062306a36Sopenharmony_ci * Complete serio port registration. 52162306a36Sopenharmony_ci * Driver core will attempt to find appropriate driver for the port. 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_cistatic void serio_add_port(struct serio *serio) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct serio *parent = serio->parent; 52662306a36Sopenharmony_ci int error; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (parent) { 52962306a36Sopenharmony_ci serio_pause_rx(parent); 53062306a36Sopenharmony_ci list_add_tail(&serio->child_node, &parent->children); 53162306a36Sopenharmony_ci serio_continue_rx(parent); 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci list_add_tail(&serio->node, &serio_list); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (serio->start) 53762306a36Sopenharmony_ci serio->start(serio); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci error = device_add(&serio->dev); 54062306a36Sopenharmony_ci if (error) 54162306a36Sopenharmony_ci dev_err(&serio->dev, 54262306a36Sopenharmony_ci "device_add() failed for %s (%s), error: %d\n", 54362306a36Sopenharmony_ci serio->phys, serio->name, error); 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci/* 54762306a36Sopenharmony_ci * serio_destroy_port() completes unregistration process and removes 54862306a36Sopenharmony_ci * port from the system 54962306a36Sopenharmony_ci */ 55062306a36Sopenharmony_cistatic void serio_destroy_port(struct serio *serio) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct serio *child; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci while ((child = serio_get_pending_child(serio)) != NULL) { 55562306a36Sopenharmony_ci serio_remove_pending_events(child); 55662306a36Sopenharmony_ci put_device(&child->dev); 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (serio->stop) 56062306a36Sopenharmony_ci serio->stop(serio); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (serio->parent) { 56362306a36Sopenharmony_ci serio_pause_rx(serio->parent); 56462306a36Sopenharmony_ci list_del_init(&serio->child_node); 56562306a36Sopenharmony_ci serio_continue_rx(serio->parent); 56662306a36Sopenharmony_ci serio->parent = NULL; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (device_is_registered(&serio->dev)) 57062306a36Sopenharmony_ci device_del(&serio->dev); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci list_del_init(&serio->node); 57362306a36Sopenharmony_ci serio_remove_pending_events(serio); 57462306a36Sopenharmony_ci put_device(&serio->dev); 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci/* 57862306a36Sopenharmony_ci * Reconnect serio port (re-initialize attached device). 57962306a36Sopenharmony_ci * If reconnect fails (old device is no longer attached or 58062306a36Sopenharmony_ci * there was no device to begin with) we do full rescan in 58162306a36Sopenharmony_ci * hope of finding a driver for the port. 58262306a36Sopenharmony_ci */ 58362306a36Sopenharmony_cistatic int serio_reconnect_port(struct serio *serio) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci int error = serio_reconnect_driver(serio); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (error) { 58862306a36Sopenharmony_ci serio_disconnect_port(serio); 58962306a36Sopenharmony_ci serio_find_driver(serio); 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci return error; 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci/* 59662306a36Sopenharmony_ci * Reconnect serio port and all its children (re-initialize attached 59762306a36Sopenharmony_ci * devices). 59862306a36Sopenharmony_ci */ 59962306a36Sopenharmony_cistatic void serio_reconnect_subtree(struct serio *root) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci struct serio *s = root; 60262306a36Sopenharmony_ci int error; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci do { 60562306a36Sopenharmony_ci error = serio_reconnect_port(s); 60662306a36Sopenharmony_ci if (!error) { 60762306a36Sopenharmony_ci /* 60862306a36Sopenharmony_ci * Reconnect was successful, move on to do the 60962306a36Sopenharmony_ci * first child. 61062306a36Sopenharmony_ci */ 61162306a36Sopenharmony_ci if (!list_empty(&s->children)) { 61262306a36Sopenharmony_ci s = list_first_entry(&s->children, 61362306a36Sopenharmony_ci struct serio, child_node); 61462306a36Sopenharmony_ci continue; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* 61962306a36Sopenharmony_ci * Either it was a leaf node or reconnect failed and it 62062306a36Sopenharmony_ci * became a leaf node. Continue reconnecting starting with 62162306a36Sopenharmony_ci * the next sibling of the parent node. 62262306a36Sopenharmony_ci */ 62362306a36Sopenharmony_ci while (s != root) { 62462306a36Sopenharmony_ci struct serio *parent = s->parent; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci if (!list_is_last(&s->child_node, &parent->children)) { 62762306a36Sopenharmony_ci s = list_entry(s->child_node.next, 62862306a36Sopenharmony_ci struct serio, child_node); 62962306a36Sopenharmony_ci break; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci s = parent; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci } while (s != root); 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci/* 63862306a36Sopenharmony_ci * serio_disconnect_port() unbinds a port from its driver. As a side effect 63962306a36Sopenharmony_ci * all children ports are unbound and destroyed. 64062306a36Sopenharmony_ci */ 64162306a36Sopenharmony_cistatic void serio_disconnect_port(struct serio *serio) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci struct serio *s = serio; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci /* 64662306a36Sopenharmony_ci * Children ports should be disconnected and destroyed 64762306a36Sopenharmony_ci * first; we travel the tree in depth-first order. 64862306a36Sopenharmony_ci */ 64962306a36Sopenharmony_ci while (!list_empty(&serio->children)) { 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* Locate a leaf */ 65262306a36Sopenharmony_ci while (!list_empty(&s->children)) 65362306a36Sopenharmony_ci s = list_first_entry(&s->children, 65462306a36Sopenharmony_ci struct serio, child_node); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci /* 65762306a36Sopenharmony_ci * Prune this leaf node unless it is the one we 65862306a36Sopenharmony_ci * started with. 65962306a36Sopenharmony_ci */ 66062306a36Sopenharmony_ci if (s != serio) { 66162306a36Sopenharmony_ci struct serio *parent = s->parent; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci device_release_driver(&s->dev); 66462306a36Sopenharmony_ci serio_destroy_port(s); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci s = parent; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* 67162306a36Sopenharmony_ci * OK, no children left, now disconnect this port. 67262306a36Sopenharmony_ci */ 67362306a36Sopenharmony_ci device_release_driver(&serio->dev); 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_civoid serio_rescan(struct serio *serio) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci serio_queue_event(serio, NULL, SERIO_RESCAN_PORT); 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ciEXPORT_SYMBOL(serio_rescan); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_civoid serio_reconnect(struct serio *serio) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci serio_queue_event(serio, NULL, SERIO_RECONNECT_SUBTREE); 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ciEXPORT_SYMBOL(serio_reconnect); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci/* 68962306a36Sopenharmony_ci * Submits register request to kseriod for subsequent execution. 69062306a36Sopenharmony_ci * Note that port registration is always asynchronous. 69162306a36Sopenharmony_ci */ 69262306a36Sopenharmony_civoid __serio_register_port(struct serio *serio, struct module *owner) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci serio_init_port(serio); 69562306a36Sopenharmony_ci serio_queue_event(serio, owner, SERIO_REGISTER_PORT); 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ciEXPORT_SYMBOL(__serio_register_port); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci/* 70062306a36Sopenharmony_ci * Synchronously unregisters serio port. 70162306a36Sopenharmony_ci */ 70262306a36Sopenharmony_civoid serio_unregister_port(struct serio *serio) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci mutex_lock(&serio_mutex); 70562306a36Sopenharmony_ci serio_disconnect_port(serio); 70662306a36Sopenharmony_ci serio_destroy_port(serio); 70762306a36Sopenharmony_ci mutex_unlock(&serio_mutex); 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ciEXPORT_SYMBOL(serio_unregister_port); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci/* 71262306a36Sopenharmony_ci * Safely unregisters children ports if they are present. 71362306a36Sopenharmony_ci */ 71462306a36Sopenharmony_civoid serio_unregister_child_port(struct serio *serio) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci struct serio *s, *next; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci mutex_lock(&serio_mutex); 71962306a36Sopenharmony_ci list_for_each_entry_safe(s, next, &serio->children, child_node) { 72062306a36Sopenharmony_ci serio_disconnect_port(s); 72162306a36Sopenharmony_ci serio_destroy_port(s); 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci mutex_unlock(&serio_mutex); 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ciEXPORT_SYMBOL(serio_unregister_child_port); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci/* 72962306a36Sopenharmony_ci * Serio driver operations 73062306a36Sopenharmony_ci */ 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_cistatic ssize_t description_show(struct device_driver *drv, char *buf) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci struct serio_driver *driver = to_serio_driver(drv); 73562306a36Sopenharmony_ci return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)"); 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_cistatic DRIVER_ATTR_RO(description); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_cistatic ssize_t bind_mode_show(struct device_driver *drv, char *buf) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci struct serio_driver *serio_drv = to_serio_driver(drv); 74262306a36Sopenharmony_ci return sprintf(buf, "%s\n", serio_drv->manual_bind ? "manual" : "auto"); 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic ssize_t bind_mode_store(struct device_driver *drv, const char *buf, size_t count) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci struct serio_driver *serio_drv = to_serio_driver(drv); 74862306a36Sopenharmony_ci int retval; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci retval = count; 75162306a36Sopenharmony_ci if (!strncmp(buf, "manual", count)) { 75262306a36Sopenharmony_ci serio_drv->manual_bind = true; 75362306a36Sopenharmony_ci } else if (!strncmp(buf, "auto", count)) { 75462306a36Sopenharmony_ci serio_drv->manual_bind = false; 75562306a36Sopenharmony_ci } else { 75662306a36Sopenharmony_ci retval = -EINVAL; 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci return retval; 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_cistatic DRIVER_ATTR_RW(bind_mode); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cistatic struct attribute *serio_driver_attrs[] = { 76462306a36Sopenharmony_ci &driver_attr_description.attr, 76562306a36Sopenharmony_ci &driver_attr_bind_mode.attr, 76662306a36Sopenharmony_ci NULL, 76762306a36Sopenharmony_ci}; 76862306a36Sopenharmony_ciATTRIBUTE_GROUPS(serio_driver); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_cistatic int serio_driver_probe(struct device *dev) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 77362306a36Sopenharmony_ci struct serio_driver *drv = to_serio_driver(dev->driver); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci return serio_connect_driver(serio, drv); 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic void serio_driver_remove(struct device *dev) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci serio_disconnect_driver(serio); 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic void serio_cleanup(struct serio *serio) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci mutex_lock(&serio->drv_mutex); 78862306a36Sopenharmony_ci if (serio->drv && serio->drv->cleanup) 78962306a36Sopenharmony_ci serio->drv->cleanup(serio); 79062306a36Sopenharmony_ci mutex_unlock(&serio->drv_mutex); 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic void serio_shutdown(struct device *dev) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci serio_cleanup(serio); 79862306a36Sopenharmony_ci} 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_cistatic void serio_attach_driver(struct serio_driver *drv) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci int error; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci error = driver_attach(&drv->driver); 80562306a36Sopenharmony_ci if (error) 80662306a36Sopenharmony_ci pr_warn("driver_attach() failed for %s with error %d\n", 80762306a36Sopenharmony_ci drv->driver.name, error); 80862306a36Sopenharmony_ci} 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ciint __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci bool manual_bind = drv->manual_bind; 81362306a36Sopenharmony_ci int error; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci drv->driver.bus = &serio_bus; 81662306a36Sopenharmony_ci drv->driver.owner = owner; 81762306a36Sopenharmony_ci drv->driver.mod_name = mod_name; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci /* 82062306a36Sopenharmony_ci * Temporarily disable automatic binding because probing 82162306a36Sopenharmony_ci * takes long time and we are better off doing it in kseriod 82262306a36Sopenharmony_ci */ 82362306a36Sopenharmony_ci drv->manual_bind = true; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci error = driver_register(&drv->driver); 82662306a36Sopenharmony_ci if (error) { 82762306a36Sopenharmony_ci pr_err("driver_register() failed for %s, error: %d\n", 82862306a36Sopenharmony_ci drv->driver.name, error); 82962306a36Sopenharmony_ci return error; 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci /* 83362306a36Sopenharmony_ci * Restore original bind mode and let kseriod bind the 83462306a36Sopenharmony_ci * driver to free ports 83562306a36Sopenharmony_ci */ 83662306a36Sopenharmony_ci if (!manual_bind) { 83762306a36Sopenharmony_ci drv->manual_bind = false; 83862306a36Sopenharmony_ci error = serio_queue_event(drv, NULL, SERIO_ATTACH_DRIVER); 83962306a36Sopenharmony_ci if (error) { 84062306a36Sopenharmony_ci driver_unregister(&drv->driver); 84162306a36Sopenharmony_ci return error; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci return 0; 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ciEXPORT_SYMBOL(__serio_register_driver); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_civoid serio_unregister_driver(struct serio_driver *drv) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci struct serio *serio; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci mutex_lock(&serio_mutex); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci drv->manual_bind = true; /* so serio_find_driver ignores it */ 85662306a36Sopenharmony_ci serio_remove_pending_events(drv); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistart_over: 85962306a36Sopenharmony_ci list_for_each_entry(serio, &serio_list, node) { 86062306a36Sopenharmony_ci if (serio->drv == drv) { 86162306a36Sopenharmony_ci serio_disconnect_port(serio); 86262306a36Sopenharmony_ci serio_find_driver(serio); 86362306a36Sopenharmony_ci /* we could've deleted some ports, restart */ 86462306a36Sopenharmony_ci goto start_over; 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci driver_unregister(&drv->driver); 86962306a36Sopenharmony_ci mutex_unlock(&serio_mutex); 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ciEXPORT_SYMBOL(serio_unregister_driver); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_cistatic void serio_set_drv(struct serio *serio, struct serio_driver *drv) 87462306a36Sopenharmony_ci{ 87562306a36Sopenharmony_ci serio_pause_rx(serio); 87662306a36Sopenharmony_ci serio->drv = drv; 87762306a36Sopenharmony_ci serio_continue_rx(serio); 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cistatic int serio_bus_match(struct device *dev, struct device_driver *drv) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 88362306a36Sopenharmony_ci struct serio_driver *serio_drv = to_serio_driver(drv); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci if (serio->manual_bind || serio_drv->manual_bind) 88662306a36Sopenharmony_ci return 0; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci return serio_match_port(serio_drv->id_table, serio); 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci#define SERIO_ADD_UEVENT_VAR(fmt, val...) \ 89262306a36Sopenharmony_ci do { \ 89362306a36Sopenharmony_ci int err = add_uevent_var(env, fmt, val); \ 89462306a36Sopenharmony_ci if (err) \ 89562306a36Sopenharmony_ci return err; \ 89662306a36Sopenharmony_ci } while (0) 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic int serio_uevent(const struct device *dev, struct kobj_uevent_env *env) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci const struct serio *serio; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if (!dev) 90362306a36Sopenharmony_ci return -ENODEV; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci serio = to_serio_port(dev); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci SERIO_ADD_UEVENT_VAR("SERIO_TYPE=%02x", serio->id.type); 90862306a36Sopenharmony_ci SERIO_ADD_UEVENT_VAR("SERIO_PROTO=%02x", serio->id.proto); 90962306a36Sopenharmony_ci SERIO_ADD_UEVENT_VAR("SERIO_ID=%02x", serio->id.id); 91062306a36Sopenharmony_ci SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X", 91362306a36Sopenharmony_ci serio->id.type, serio->id.proto, serio->id.id, serio->id.extra); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if (serio->firmware_id[0]) 91662306a36Sopenharmony_ci SERIO_ADD_UEVENT_VAR("SERIO_FIRMWARE_ID=%s", 91762306a36Sopenharmony_ci serio->firmware_id); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci return 0; 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci#undef SERIO_ADD_UEVENT_VAR 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci#ifdef CONFIG_PM 92462306a36Sopenharmony_cistatic int serio_suspend(struct device *dev) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci serio_cleanup(serio); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci return 0; 93162306a36Sopenharmony_ci} 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_cistatic int serio_resume(struct device *dev) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci struct serio *serio = to_serio_port(dev); 93662306a36Sopenharmony_ci int error = -ENOENT; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci mutex_lock(&serio->drv_mutex); 93962306a36Sopenharmony_ci if (serio->drv && serio->drv->fast_reconnect) { 94062306a36Sopenharmony_ci error = serio->drv->fast_reconnect(serio); 94162306a36Sopenharmony_ci if (error && error != -ENOENT) 94262306a36Sopenharmony_ci dev_warn(dev, "fast reconnect failed with error %d\n", 94362306a36Sopenharmony_ci error); 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci mutex_unlock(&serio->drv_mutex); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci if (error) { 94862306a36Sopenharmony_ci /* 94962306a36Sopenharmony_ci * Driver reconnect can take a while, so better let 95062306a36Sopenharmony_ci * kseriod deal with it. 95162306a36Sopenharmony_ci */ 95262306a36Sopenharmony_ci serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT); 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci return 0; 95662306a36Sopenharmony_ci} 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_cistatic const struct dev_pm_ops serio_pm_ops = { 95962306a36Sopenharmony_ci .suspend = serio_suspend, 96062306a36Sopenharmony_ci .resume = serio_resume, 96162306a36Sopenharmony_ci .poweroff = serio_suspend, 96262306a36Sopenharmony_ci .restore = serio_resume, 96362306a36Sopenharmony_ci}; 96462306a36Sopenharmony_ci#endif /* CONFIG_PM */ 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci/* called from serio_driver->connect/disconnect methods under serio_mutex */ 96762306a36Sopenharmony_ciint serio_open(struct serio *serio, struct serio_driver *drv) 96862306a36Sopenharmony_ci{ 96962306a36Sopenharmony_ci serio_set_drv(serio, drv); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci if (serio->open && serio->open(serio)) { 97262306a36Sopenharmony_ci serio_set_drv(serio, NULL); 97362306a36Sopenharmony_ci return -1; 97462306a36Sopenharmony_ci } 97562306a36Sopenharmony_ci return 0; 97662306a36Sopenharmony_ci} 97762306a36Sopenharmony_ciEXPORT_SYMBOL(serio_open); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci/* called from serio_driver->connect/disconnect methods under serio_mutex */ 98062306a36Sopenharmony_civoid serio_close(struct serio *serio) 98162306a36Sopenharmony_ci{ 98262306a36Sopenharmony_ci if (serio->close) 98362306a36Sopenharmony_ci serio->close(serio); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci serio_set_drv(serio, NULL); 98662306a36Sopenharmony_ci} 98762306a36Sopenharmony_ciEXPORT_SYMBOL(serio_close); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ciirqreturn_t serio_interrupt(struct serio *serio, 99062306a36Sopenharmony_ci unsigned char data, unsigned int dfl) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci unsigned long flags; 99362306a36Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci spin_lock_irqsave(&serio->lock, flags); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci if (likely(serio->drv)) { 99862306a36Sopenharmony_ci ret = serio->drv->interrupt(serio, data, dfl); 99962306a36Sopenharmony_ci } else if (!dfl && device_is_registered(&serio->dev)) { 100062306a36Sopenharmony_ci serio_rescan(serio); 100162306a36Sopenharmony_ci ret = IRQ_HANDLED; 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci spin_unlock_irqrestore(&serio->lock, flags); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci return ret; 100762306a36Sopenharmony_ci} 100862306a36Sopenharmony_ciEXPORT_SYMBOL(serio_interrupt); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_cistruct bus_type serio_bus = { 101162306a36Sopenharmony_ci .name = "serio", 101262306a36Sopenharmony_ci .drv_groups = serio_driver_groups, 101362306a36Sopenharmony_ci .match = serio_bus_match, 101462306a36Sopenharmony_ci .uevent = serio_uevent, 101562306a36Sopenharmony_ci .probe = serio_driver_probe, 101662306a36Sopenharmony_ci .remove = serio_driver_remove, 101762306a36Sopenharmony_ci .shutdown = serio_shutdown, 101862306a36Sopenharmony_ci#ifdef CONFIG_PM 101962306a36Sopenharmony_ci .pm = &serio_pm_ops, 102062306a36Sopenharmony_ci#endif 102162306a36Sopenharmony_ci}; 102262306a36Sopenharmony_ciEXPORT_SYMBOL(serio_bus); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_cistatic int __init serio_init(void) 102562306a36Sopenharmony_ci{ 102662306a36Sopenharmony_ci int error; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci error = bus_register(&serio_bus); 102962306a36Sopenharmony_ci if (error) { 103062306a36Sopenharmony_ci pr_err("Failed to register serio bus, error: %d\n", error); 103162306a36Sopenharmony_ci return error; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci return 0; 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_cistatic void __exit serio_exit(void) 103862306a36Sopenharmony_ci{ 103962306a36Sopenharmony_ci bus_unregister(&serio_bus); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci /* 104262306a36Sopenharmony_ci * There should not be any outstanding events but work may 104362306a36Sopenharmony_ci * still be scheduled so simply cancel it. 104462306a36Sopenharmony_ci */ 104562306a36Sopenharmony_ci cancel_work_sync(&serio_event_work); 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_cisubsys_initcall(serio_init); 104962306a36Sopenharmony_cimodule_exit(serio_exit); 1050