1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * Copyright(c) 2015, 2016 Intel Corporation. 4 */ 5 6 #include <linux/cdev.h> 7 #include <linux/device.h> 8 #include <linux/fs.h> 9 10 #include "hfi.h" 11 #include "device.h" 12 13 static char *hfi1_user_devnode(const struct device *dev, umode_t *mode) 14 { 15 if (mode) 16 *mode = 0666; 17 return kasprintf(GFP_KERNEL, "%s", dev_name(dev)); 18 } 19 20 static const struct class user_class = { 21 .name = "hfi1_user", 22 .devnode = hfi1_user_devnode, 23 }; 24 static dev_t hfi1_dev; 25 26 int hfi1_cdev_init(int minor, const char *name, 27 const struct file_operations *fops, 28 struct cdev *cdev, struct device **devp, 29 struct kobject *parent) 30 { 31 const dev_t dev = MKDEV(MAJOR(hfi1_dev), minor); 32 struct device *device = NULL; 33 int ret; 34 35 cdev_init(cdev, fops); 36 cdev->owner = THIS_MODULE; 37 cdev_set_parent(cdev, parent); 38 kobject_set_name(&cdev->kobj, name); 39 40 ret = cdev_add(cdev, dev, 1); 41 if (ret < 0) { 42 pr_err("Could not add cdev for minor %d, %s (err %d)\n", 43 minor, name, -ret); 44 goto done; 45 } 46 47 device = device_create(&user_class, NULL, dev, NULL, "%s", name); 48 49 if (IS_ERR(device)) { 50 ret = PTR_ERR(device); 51 pr_err("Could not create device for minor %d, %s (err %pe)\n", 52 minor, name, device); 53 device = NULL; 54 cdev_del(cdev); 55 } 56 done: 57 *devp = device; 58 return ret; 59 } 60 61 void hfi1_cdev_cleanup(struct cdev *cdev, struct device **devp) 62 { 63 struct device *device = *devp; 64 65 if (device) { 66 device_unregister(device); 67 *devp = NULL; 68 69 cdev_del(cdev); 70 } 71 } 72 73 static const char *hfi1_class_name = "hfi1"; 74 75 const char *class_name(void) 76 { 77 return hfi1_class_name; 78 } 79 80 int __init dev_init(void) 81 { 82 int ret; 83 84 ret = alloc_chrdev_region(&hfi1_dev, 0, HFI1_NMINORS, DRIVER_NAME); 85 if (ret < 0) { 86 pr_err("Could not allocate chrdev region (err %d)\n", -ret); 87 return ret; 88 } 89 90 ret = class_register(&user_class); 91 if (ret) { 92 pr_err("Could not create device class for user accessible files (err %d)\n", 93 -ret); 94 unregister_chrdev_region(hfi1_dev, HFI1_NMINORS); 95 } 96 97 return ret; 98 } 99 100 void dev_cleanup(void) 101 { 102 class_unregister(&user_class); 103 unregister_chrdev_region(hfi1_dev, HFI1_NMINORS); 104 } 105