/* * Copyright (C) 2016 Samsung Electronics, Inc. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include "tz_cdev.h" static atomic_t tz_cdev_state = ATOMIC_INIT(0); int tz_cdev_register(struct tz_cdev *cdev) { int err; err = alloc_chrdev_region(&cdev->dev, 0, 1, cdev->name); if (unlikely(err)) return err; cdev->class = class_create(cdev->owner, cdev->name); if (IS_ERR(cdev->class)) { err = PTR_ERR(cdev->class); goto class_create_failed; } cdev_init(&cdev->cdev, cdev->fops); err = cdev_add(&cdev->cdev, cdev->dev, 1); if (unlikely(err)) goto cdev_add_failed; cdev->device = device_create(cdev->class, NULL, cdev->dev, NULL, cdev->name); if (IS_ERR(cdev->device)) { err = PTR_ERR(cdev->device); goto device_create_failed; } atomic_set(&tz_cdev_state, 1); return 0; device_create_failed: cdev_del(&cdev->cdev); cdev_add_failed: class_destroy(cdev->class); class_create_failed: unregister_chrdev_region(cdev->dev, 1); return err; } void tz_cdev_unregister(struct tz_cdev *cdev) { if (!atomic_cmpxchg(&tz_cdev_state, 1, 0)) return; device_destroy(cdev->class, cdev->dev); cdev_del(&cdev->cdev); class_destroy(cdev->class); unregister_chrdev_region(cdev->dev, 1); }