diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index 04aab9ddebb6..720e21950e44 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -86,7 +86,7 @@ struct cserial { struct f_cdev { struct cdev fcdev_cdev; - struct device *dev; + struct device dev; unsigned int port_num; char name[sizeof(DEVICE_NAME) + 2]; int minor; @@ -894,13 +894,16 @@ static void cser_free_inst(struct usb_function_instance *fi) opts = container_of(fi, struct f_cdev_opts, func_inst); if (opts->port) { - device_destroy(fcdev_classp, MKDEV(major, opts->port->minor)); - cdev_del(&opts->port->fcdev_cdev); + cdev_device_del(&opts->port->fcdev_cdev, &opts->port->dev); + mutex_lock(&chardev_ida_lock); + ida_simple_remove(&chardev_ida, opts->port->minor); + mutex_unlock(&chardev_ida_lock); usb_cser_debugfs_exit(opts->port); + put_device(&opts->port->dev); } + usb_cser_chardev_deinit(); kfree(opts->func_name); - kfree(opts->port); kfree(opts); } @@ -1140,13 +1143,10 @@ int f_cdev_open(struct inode *inode, struct file *file) struct f_cdev *port; port = container_of(inode->i_cdev, struct f_cdev, fcdev_cdev); - if (!port) { - pr_err("Port is NULL.\n"); - return -EINVAL; - } - - if (port && port->port_open) { + get_device(&port->dev); + if (port->port_open) { pr_err("port is already opened.\n"); + put_device(&port->dev); return -EBUSY; } @@ -1156,6 +1156,7 @@ int f_cdev_open(struct inode *inode, struct file *file) port->is_connected); if (ret) { pr_debug("open interrupted.\n"); + put_device(&port->dev); return ret; } @@ -1175,16 +1176,12 @@ int f_cdev_release(struct inode *inode, struct file *file) struct f_cdev *port; port = file->private_data; - if (!port) { - pr_err("port is NULL.\n"); - return -EINVAL; - } - spin_lock_irqsave(&port->port_lock, flags); port->port_open = false; port->cbits_updated = false; spin_unlock_irqrestore(&port->port_lock, flags); pr_debug("port(%s)(%pK) is closed.\n", port->name, port); + put_device(&port->dev); return 0; } @@ -1753,11 +1750,17 @@ static void usb_cser_debugfs_exit(struct f_cdev *port) debugfs_remove_recursive(port->debugfs_root); } +static void cdev_device_release(struct device *dev) +{ + struct f_cdev *port = container_of(dev, struct f_cdev, dev); + + pr_debug("Free cdev port(%d)\n", port->port_num); + kfree(port); +} + static struct f_cdev *f_cdev_alloc(char *func_name, int portno) { int ret; - dev_t dev; - struct device *device; struct f_cdev *port; port = kzalloc(sizeof(struct f_cdev), GFP_KERNEL); @@ -1807,27 +1810,24 @@ static struct f_cdev *f_cdev_alloc(char *func_name, int portno) /* create char device */ cdev_init(&port->fcdev_cdev, &f_cdev_fops); - dev = MKDEV(major, port->minor); - ret = cdev_add(&port->fcdev_cdev, dev, 1); + device_initialize(&port->dev); + port->dev.class = fcdev_classp; + port->dev.parent = NULL; + port->dev.release = cdev_device_release; + port->dev.devt = MKDEV(major, port->minor); + dev_set_name(&port->dev, port->name); + ret = cdev_device_add(&port->fcdev_cdev, &port->dev); if (ret) { pr_err("Failed to add cdev for port(%s)\n", port->name); goto err_cdev_add; } - device = device_create(fcdev_classp, NULL, dev, NULL, port->name); - if (IS_ERR(device)) { - ret = PTR_ERR(device); - goto err_create_dev; - } - usb_cser_debugfs_init(port); pr_info("port_name:%s (%pK) portno:(%d)\n", port->name, port, port->port_num); return port; -err_create_dev: - cdev_del(&port->fcdev_cdev); err_cdev_add: destroy_workqueue(port->fcdev_wq); err_get_ida: