summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pnp/core.c53
1 files changed, 40 insertions, 13 deletions
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index ef2f59c4e57c..b54620e53830 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -42,6 +42,13 @@ void *pnp_alloc(long size)
return result;
}
+static void pnp_remove_protocol(struct pnp_protocol *protocol)
+{
+ mutex_lock(&pnp_lock);
+ list_del(&protocol->protocol_list);
+ mutex_unlock(&pnp_lock);
+}
+
/**
* pnp_protocol_register - adds a pnp protocol to the pnp layer
* @protocol: pointer to the corresponding pnp_protocol structure
@@ -50,12 +57,13 @@ void *pnp_alloc(long size)
*/
int pnp_register_protocol(struct pnp_protocol *protocol)
{
- int nodenum;
struct list_head *pos;
+ int nodenum, ret;
INIT_LIST_HEAD(&protocol->devices);
INIT_LIST_HEAD(&protocol->cards);
nodenum = 0;
+
mutex_lock(&pnp_lock);
/* assign the lowest unused number */
@@ -67,12 +75,18 @@ int pnp_register_protocol(struct pnp_protocol *protocol)
}
}
+ protocol->number = nodenum;
+ dev_set_name(&protocol->dev, "pnp%d", nodenum);
+
list_add_tail(&protocol->protocol_list, &pnp_protocols);
+
mutex_unlock(&pnp_lock);
- protocol->number = nodenum;
- dev_set_name(&protocol->dev, "pnp%d", nodenum);
- return device_register(&protocol->dev);
+ ret = device_register(&protocol->dev);
+ if (ret)
+ pnp_remove_protocol(protocol);
+
+ return ret;
}
/**
@@ -81,9 +95,7 @@ int pnp_register_protocol(struct pnp_protocol *protocol)
*/
void pnp_unregister_protocol(struct pnp_protocol *protocol)
{
- mutex_lock(&pnp_lock);
- list_del(&protocol->protocol_list);
- mutex_unlock(&pnp_lock);
+ pnp_remove_protocol(protocol);
device_unregister(&protocol->dev);
}
@@ -158,18 +170,36 @@ struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id,
return dev;
}
+static void pnp_delist_device(struct pnp_dev *dev)
+{
+ mutex_lock(&pnp_lock);
+ list_del(&dev->global_list);
+ list_del(&dev->protocol_list);
+ mutex_unlock(&pnp_lock);
+}
+
int __pnp_add_device(struct pnp_dev *dev)
{
+ int ret;
+
pnp_fixup_device(dev);
dev->status = PNP_READY;
+
mutex_lock(&pnp_lock);
+
list_add_tail(&dev->global_list, &pnp_global);
list_add_tail(&dev->protocol_list, &dev->protocol->devices);
+
mutex_unlock(&pnp_lock);
- if (dev->protocol->can_wakeup)
+
+ ret = device_register(&dev->dev);
+ if (ret)
+ pnp_delist_device(dev);
+ else if (dev->protocol->can_wakeup)
device_set_wakeup_capable(&dev->dev,
dev->protocol->can_wakeup(dev));
- return device_register(&dev->dev);
+
+ return ret;
}
/*
@@ -204,10 +234,7 @@ int pnp_add_device(struct pnp_dev *dev)
void __pnp_remove_device(struct pnp_dev *dev)
{
- mutex_lock(&pnp_lock);
- list_del(&dev->global_list);
- list_del(&dev->protocol_list);
- mutex_unlock(&pnp_lock);
+ pnp_delist_device(dev);
device_unregister(&dev->dev);
}