@@ -909,6 +909,7 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
if (idx < 0)
return idx;
+ get_device(&edev->dev);
spin_lock_irqsave(&edev->lock, flags);
ret = raw_notifier_chain_register(&edev->nh[idx], nb);
spin_unlock_irqrestore(&edev->lock, flags);
@@ -941,6 +942,7 @@ int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id,
spin_lock_irqsave(&edev->lock, flags);
ret = raw_notifier_chain_unregister(&edev->nh[idx], nb);
spin_unlock_irqrestore(&edev->lock, flags);
+ put_device(&edev->dev);
return ret;
}
@@ -967,6 +969,7 @@ int extcon_register_notifier_all(struct extcon_dev *edev,
if (!edev || !nb)
return -EINVAL;
+ get_device(&edev->dev);
spin_lock_irqsave(&edev->lock, flags);
ret = raw_notifier_chain_register(&edev->nh_all, nb);
spin_unlock_irqrestore(&edev->lock, flags);
@@ -994,6 +997,7 @@ int extcon_unregister_notifier_all(struct extcon_dev *edev,
spin_lock_irqsave(&edev->lock, flags);
ret = raw_notifier_chain_unregister(&edev->nh_all, nb);
spin_unlock_irqrestore(&edev->lock, flags);
+ put_device(&edev->dev);
return ret;
}
@@ -1020,6 +1024,13 @@ static int create_extcon_class(void)
static void extcon_dev_release(struct device *dev)
{
+ struct extcon_dev *edev = container_of(dev, struct extcon_dev, dev);
+
+ dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
+
+ kfree(edev->nh);
+ kfree(edev->supported_cable);
+ kfree(edev);
}
static const char *muex_name = "mutually_exclusive";
@@ -1041,6 +1052,7 @@ static void dummy_sysfs_dev_release(struct device *dev)
struct extcon_dev *extcon_dev_allocate(const unsigned int *supported_cable)
{
struct extcon_dev *edev;
+ int index = 0;
if (!supported_cable)
return ERR_PTR(-EINVAL);
@@ -1049,8 +1061,18 @@ struct extcon_dev *extcon_dev_allocate(const unsigned int *supported_cable)
if (!edev)
return ERR_PTR(-ENOMEM);
- edev->max_supported = 0;
- edev->supported_cable = supported_cable;
+ for (; supported_cable[index] != EXTCON_NONE; index++)
+ ;
+
+ edev->max_supported = index;
+ edev->supported_cable = kmemdup(supported_cable,
+ (index + 1) * sizeof(*supported_cable),
+ GFP_KERNEL);
+
+ if (!edev->supported_cable) {
+ kfree(edev);
+ return ERR_PTR(-ENOMEM);
+ }
return edev;
}
@@ -1058,10 +1080,11 @@ struct extcon_dev *extcon_dev_allocate(const unsigned int *supported_cable)
/*
* extcon_dev_free() - Free the memory of extcon device.
* @edev: the extcon device
+ *
+ * TODO: useless now, may delete later
*/
void extcon_dev_free(struct extcon_dev *edev)
{
- kfree(edev);
}
EXPORT_SYMBOL_GPL(extcon_dev_free);
@@ -1081,25 +1104,25 @@ EXPORT_SYMBOL_GPL(extcon_dev_free);
*/
int extcon_dev_register(struct extcon_dev *edev)
{
- int ret, index = 0;
+ int ret, index;
static atomic_t edev_no = ATOMIC_INIT(-1);
if (!extcon_class) {
ret = create_extcon_class();
if (ret < 0)
- return ret;
+ goto free_edev;
}
- if (!edev || !edev->supported_cable)
- return -EINVAL;
-
- for (; edev->supported_cable[index] != EXTCON_NONE; index++);
+ if (!edev || !edev->supported_cable) {
+ ret = -EINVAL;
+ goto free_edev;
+ }
- edev->max_supported = index;
- if (index > SUPPORTED_CABLE_MAX) {
+ if (edev->max_supported > SUPPORTED_CABLE_MAX) {
dev_err(&edev->dev,
"exceed the maximum number of supported cables\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_edev;
}
edev->dev.class = extcon_class;
@@ -1109,7 +1132,8 @@ int extcon_dev_register(struct extcon_dev *edev)
if (IS_ERR_OR_NULL(edev->name)) {
dev_err(&edev->dev,
"extcon device name is null\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_edev;
}
dev_set_name(&edev->dev, "extcon%lu",
(unsigned long)atomic_inc_return(&edev_no));
@@ -1123,7 +1147,7 @@ int extcon_dev_register(struct extcon_dev *edev)
GFP_KERNEL);
if (!edev->cables) {
ret = -ENOMEM;
- goto err_sysfs_alloc;
+ goto free_edev;
}
for (index = 0; index < edev->max_supported; index++) {
cable = &edev->cables[index];
@@ -1237,8 +1261,7 @@ int extcon_dev_register(struct extcon_dev *edev)
}
spin_lock_init(&edev->lock);
- edev->nh = devm_kcalloc(&edev->dev, edev->max_supported,
- sizeof(*edev->nh), GFP_KERNEL);
+ edev->nh = kcalloc(edev->max_supported, sizeof(*edev->nh), GFP_KERNEL);
if (!edev->nh) {
ret = -ENOMEM;
goto err_dev;
@@ -1274,7 +1297,8 @@ int extcon_dev_register(struct extcon_dev *edev)
err_alloc_cables:
if (edev->max_supported)
kfree(edev->cables);
-err_sysfs_alloc:
+free_edev:
+ kfree(edev);
return ret;
}
EXPORT_SYMBOL_GPL(extcon_dev_register);
@@ -1283,8 +1307,6 @@ EXPORT_SYMBOL_GPL(extcon_dev_register);
* extcon_dev_unregister() - Unregister the extcon device.
* @edev: the extcon device to be unregistered.
*
- * Note that this does not call kfree(edev) because edev was not allocated
- * by this class.
*/
void extcon_dev_unregister(struct extcon_dev *edev)
{
@@ -41,7 +41,7 @@
struct extcon_dev {
/* Optional user initializing data */
const char *name;
- const unsigned int *supported_cable;
+ unsigned int *supported_cable;
const u32 *mutually_exclusive;
/* Internal data. Please do not set. */