#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/kthread.h>
+#include <linux/mutex.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Serio abstraction core");
EXPORT_SYMBOL(serio_reconnect);
/*
- * serio_sem protects entire serio subsystem and is taken every time
+ * serio_mutex protects entire serio subsystem and is taken every time
* serio port or driver registrered or unregistered.
*/
-static DECLARE_MUTEX(serio_sem);
+static DEFINE_MUTEX(serio_mutex);
static LIST_HEAD(serio_list);
-static struct bus_type serio_bus = {
- .name = "serio",
-};
+static struct bus_type serio_bus;
+static void serio_add_driver(struct serio_driver *drv);
static void serio_add_port(struct serio *serio);
static void serio_destroy_port(struct serio *serio);
static void serio_reconnect_port(struct serio *serio);
{
int retval;
- down(&serio->drv_sem);
+ mutex_lock(&serio->drv_mutex);
retval = drv->connect(serio, drv);
- up(&serio->drv_sem);
+ mutex_unlock(&serio->drv_mutex);
return retval;
}
{
int retval = -1;
- down(&serio->drv_sem);
+ mutex_lock(&serio->drv_mutex);
if (serio->drv && serio->drv->reconnect)
retval = serio->drv->reconnect(serio);
- up(&serio->drv_sem);
+ mutex_unlock(&serio->drv_mutex);
return retval;
}
static void serio_disconnect_driver(struct serio *serio)
{
- down(&serio->drv_sem);
+ mutex_lock(&serio->drv_mutex);
if (serio->drv)
serio->drv->disconnect(serio);
- up(&serio->drv_sem);
+ mutex_unlock(&serio->drv_mutex);
}
static int serio_match_port(const struct serio_device_id *ids, struct serio *serio)
static void serio_find_driver(struct serio *serio)
{
+ int error;
+
down_write(&serio_bus.subsys.rwsem);
- device_attach(&serio->dev);
+ error = device_attach(&serio->dev);
+ if (error < 0)
+ printk(KERN_WARNING
+ "serio: device_attach() failed for %s (%s), error: %d\n",
+ serio->phys, serio->name, error);
up_write(&serio_bus.subsys.rwsem);
}
if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) {
if (!try_module_get(owner)) {
printk(KERN_WARNING "serio: Can't get module reference, dropping event %d\n", event_type);
+ kfree(event);
goto out;
}
static void serio_handle_event(void)
{
struct serio_event *event;
- struct serio_driver *serio_drv;
- down(&serio_sem);
+ mutex_lock(&serio_mutex);
/*
* Note that we handle only one event here to give swsusp
break;
case SERIO_REGISTER_DRIVER:
- serio_drv = event->object;
- driver_register(&serio_drv->driver);
+ serio_add_driver(event->object);
break;
default:
serio_free_event(event);
}
- up(&serio_sem);
+ mutex_unlock(&serio_mutex);
}
/*
struct device_driver *drv;
int retval;
- retval = down_interruptible(&serio_sem);
+ retval = mutex_lock_interruptible(&serio_mutex);
if (retval)
return retval;
retval = -EINVAL;
}
- up(&serio_sem);
+ mutex_unlock(&serio_mutex);
return retval;
}
__module_get(THIS_MODULE);
+ INIT_LIST_HEAD(&serio->node);
spin_lock_init(&serio->lock);
- init_MUTEX(&serio->drv_sem);
+ mutex_init(&serio->drv_mutex);
device_initialize(&serio->dev);
snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id),
"serio%ld", (long)atomic_inc_return(&serio_no) - 1);
*/
static void serio_add_port(struct serio *serio)
{
+ int error;
+
if (serio->parent) {
serio_pause_rx(serio->parent);
serio->parent->child = serio;
list_add_tail(&serio->node, &serio_list);
if (serio->start)
serio->start(serio);
- device_add(&serio->dev);
- sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group);
- serio->registered = 1;
+ error = device_add(&serio->dev);
+ if (error)
+ printk(KERN_ERR
+ "serio: device_add() failed for %s (%s), error: %d\n",
+ serio->phys, serio->name, error);
+ else {
+ serio->registered = 1;
+ error = sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group);
+ if (error)
+ printk(KERN_ERR
+ "serio: sysfs_create_group() failed for %s (%s), error: %d\n",
+ serio->phys, serio->name, error);
+ }
}
/*
if (serio->registered) {
sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group);
device_del(&serio->dev);
- list_del_init(&serio->node);
serio->registered = 0;
}
+ list_del_init(&serio->node);
serio_remove_pending_events(serio);
put_device(&serio->dev);
}
*/
void serio_unregister_port(struct serio *serio)
{
- down(&serio_sem);
+ mutex_lock(&serio_mutex);
serio_disconnect_port(serio);
serio_destroy_port(serio);
- up(&serio_sem);
+ mutex_unlock(&serio_mutex);
}
/*
*/
void serio_unregister_child_port(struct serio *serio)
{
- down(&serio_sem);
+ mutex_lock(&serio_mutex);
if (serio->child) {
serio_disconnect_port(serio->child);
serio_destroy_port(serio->child);
}
- up(&serio_sem);
+ mutex_unlock(&serio_mutex);
}
/*
* Submits register request to kseriod for subsequent execution.
- * Can be used when it is not obvious whether the serio_sem is
+ * Can be used when it is not obvious whether the serio_mutex is
* taken or not and when delayed execution is feasible.
*/
void __serio_unregister_port_delayed(struct serio *serio, struct module *owner)
return 0;
}
+static struct bus_type serio_bus = {
+ .name = "serio",
+ .probe = serio_driver_probe,
+ .remove = serio_driver_remove,
+};
+
+static void serio_add_driver(struct serio_driver *drv)
+{
+ int error;
+
+ error = driver_register(&drv->driver);
+ if (error)
+ printk(KERN_ERR
+ "serio: driver_register() failed for %s, error: %d\n",
+ drv->driver.name, error);
+}
+
void __serio_register_driver(struct serio_driver *drv, struct module *owner)
{
drv->driver.bus = &serio_bus;
- drv->driver.probe = serio_driver_probe;
- drv->driver.remove = serio_driver_remove;
serio_queue_event(drv, owner, SERIO_REGISTER_DRIVER);
}
{
struct serio *serio;
- down(&serio_sem);
+ mutex_lock(&serio_mutex);
drv->manual_bind = 1; /* so serio_find_driver ignores it */
start_over:
}
driver_unregister(&drv->driver);
- up(&serio_sem);
+ mutex_unlock(&serio_mutex);
}
static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
#ifdef CONFIG_HOTPLUG
-#define SERIO_ADD_HOTPLUG_VAR(fmt, val...) \
+#define SERIO_ADD_UEVENT_VAR(fmt, val...) \
do { \
- int err = add_hotplug_env_var(envp, num_envp, &i, \
+ int err = add_uevent_var(envp, num_envp, &i, \
buffer, buffer_size, &len, \
fmt, val); \
if (err) \
return err; \
} while (0)
-static int serio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
{
struct serio *serio;
int i = 0;
serio = to_serio_port(dev);
- SERIO_ADD_HOTPLUG_VAR("SERIO_TYPE=%02x", serio->id.type);
- SERIO_ADD_HOTPLUG_VAR("SERIO_PROTO=%02x", serio->id.proto);
- SERIO_ADD_HOTPLUG_VAR("SERIO_ID=%02x", serio->id.id);
- SERIO_ADD_HOTPLUG_VAR("SERIO_EXTRA=%02x", serio->id.extra);
- SERIO_ADD_HOTPLUG_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X",
+ SERIO_ADD_UEVENT_VAR("SERIO_TYPE=%02x", serio->id.type);
+ SERIO_ADD_UEVENT_VAR("SERIO_PROTO=%02x", serio->id.proto);
+ SERIO_ADD_UEVENT_VAR("SERIO_ID=%02x", serio->id.id);
+ SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra);
+ SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X",
serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);
envp[i] = NULL;
return 0;
}
-#undef SERIO_ADD_HOTPLUG_VAR
+#undef SERIO_ADD_UEVENT_VAR
#else
-static int serio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
{
return -ENODEV;
}
return 0;
}
-/* called from serio_driver->connect/disconnect methods under serio_sem */
+/* called from serio_driver->connect/disconnect methods under serio_mutex */
int serio_open(struct serio *serio, struct serio_driver *drv)
{
serio_set_drv(serio, drv);
return 0;
}
-/* called from serio_driver->connect/disconnect methods under serio_sem */
+/* called from serio_driver->connect/disconnect methods under serio_mutex */
void serio_close(struct serio *serio)
{
if (serio->close)
static int __init serio_init(void)
{
- serio_task = kthread_run(serio_thread, NULL, "kseriod");
- if (IS_ERR(serio_task)) {
- printk(KERN_ERR "serio: Failed to start kseriod\n");
- return PTR_ERR(serio_task);
- }
+ int error;
serio_bus.dev_attrs = serio_device_attrs;
serio_bus.drv_attrs = serio_driver_attrs;
serio_bus.match = serio_bus_match;
- serio_bus.hotplug = serio_hotplug;
+ serio_bus.uevent = serio_uevent;
serio_bus.resume = serio_resume;
- bus_register(&serio_bus);
+ error = bus_register(&serio_bus);
+ if (error) {
+ printk(KERN_ERR "serio: failed to register serio bus, error: %d\n", error);
+ return error;
+ }
+
+ serio_task = kthread_run(serio_thread, NULL, "kseriod");
+ if (IS_ERR(serio_task)) {
+ bus_unregister(&serio_bus);
+ error = PTR_ERR(serio_task);
+ printk(KERN_ERR "serio: Failed to start kseriod, error: %d\n", error);
+ return error;
+ }
return 0;
}
kthread_stop(serio_task);
}
-module_init(serio_init);
+subsys_initcall(serio_init);
module_exit(serio_exit);