* struct wwan_device - The structure that defines a WWAN device
*
* @id: WWAN device unique ID.
+ * @refcount: Reference count of this WWAN device. When this refcount reaches
+ * zero, the device is deleted. NB: access is protected by global
+ * wwan_register_lock mutex.
* @dev: Underlying device.
* @ops: wwan device ops
* @ops_ctxt: context to pass to ops
*/
struct wwan_device {
unsigned int id;
+ int refcount;
struct device dev;
const struct wwan_ops *ops;
void *ops_ctxt;
/* If wwandev already exists, return it */
wwandev = wwan_dev_get_by_parent(parent);
- if (!IS_ERR(wwandev))
+ if (!IS_ERR(wwandev)) {
+ wwandev->refcount++;
goto done_unlock;
+ }
id = ida_alloc(&wwan_dev_ids, GFP_KERNEL);
if (id < 0) {
wwandev->dev.class = &wwan_class;
wwandev->dev.type = &wwan_dev_type;
wwandev->id = id;
+ wwandev->refcount = 1;
dev_set_name(&wwandev->dev, "wwan%d", wwandev->id);
err = device_register(&wwandev->dev);
return wwandev;
}
-static int is_wwan_child(struct device *dev, void *data)
-{
- return dev->class == &wwan_class;
-}
-
static void wwan_remove_dev(struct wwan_device *wwandev)
{
- int ret;
-
/* Prevent concurrent picking from wwan_create_dev */
mutex_lock(&wwan_register_lock);
- /* WWAN device is created and registered (get+add) along with its first
- * child port, and subsequent port registrations only grab a reference
- * (get). The WWAN device must then be unregistered (del+put) along with
- * its last port, and reference simply dropped (put) otherwise. In the
- * same fashion, we must not unregister it when the ops are still there.
- */
- if (wwandev->ops)
- ret = 1;
- else
- ret = device_for_each_child(&wwandev->dev, NULL, is_wwan_child);
+ if (--wwandev->refcount <= 0) {
+ struct device *child = device_find_any_child(&wwandev->dev);
+
+ put_device(child);
+ if (WARN_ON(wwandev->ops || child)) /* Paranoid */
+ goto out_unlock;
- if (!ret) {
#ifdef CONFIG_WWAN_DEBUGFS
debugfs_remove_recursive(wwandev->debugfs_dir);
#endif
put_device(&wwandev->dev);
}
+out_unlock:
mutex_unlock(&wwan_register_lock);
}