root/drivers/staging/fieldbus/dev_core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. online_show
  2. enabled_show
  3. enabled_store
  4. card_name_show
  5. read_area_size_show
  6. write_area_size_show
  7. fieldbus_id_show
  8. fieldbus_type_show
  9. fieldbus_is_visible
  10. fieldbus_open
  11. fieldbus_release
  12. fieldbus_read
  13. fieldbus_write
  14. fieldbus_poll
  15. fieldbus_dev_area_updated
  16. fieldbus_dev_online_changed
  17. __fieldbus_dev_unregister
  18. fieldbus_dev_unregister
  19. __fieldbus_dev_register
  20. fieldbus_dev_register
  21. fieldbus_init
  22. fieldbus_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Fieldbus Device Driver Core
   4  *
   5  */
   6 
   7 #include <linux/mutex.h>
   8 #include <linux/module.h>
   9 #include <linux/device.h>
  10 #include <linux/idr.h>
  11 #include <linux/fs.h>
  12 #include <linux/slab.h>
  13 #include <linux/poll.h>
  14 
  15 /* move to <linux/fieldbus_dev.h> when taking this out of staging */
  16 #include "fieldbus_dev.h"
  17 
  18 /* Maximum number of fieldbus devices */
  19 #define MAX_FIELDBUSES          32
  20 
  21 /* the dev_t structure to store the dynamically allocated fieldbus devices */
  22 static dev_t fieldbus_devt;
  23 static DEFINE_IDA(fieldbus_ida);
  24 static DEFINE_MUTEX(fieldbus_mtx);
  25 
  26 static const char ctrl_enabled[] = "enabled";
  27 static const char ctrl_disabled[] = "disabled";
  28 
  29 static ssize_t online_show(struct device *dev, struct device_attribute *attr,
  30                            char *buf)
  31 {
  32         struct fieldbus_dev *fb = dev_get_drvdata(dev);
  33 
  34         return sprintf(buf, "%d\n", !!fb->online);
  35 }
  36 static DEVICE_ATTR_RO(online);
  37 
  38 static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
  39                             char *buf)
  40 {
  41         struct fieldbus_dev *fb = dev_get_drvdata(dev);
  42 
  43         if (!fb->enable_get)
  44                 return -EINVAL;
  45         return sprintf(buf, "%d\n", !!fb->enable_get(fb));
  46 }
  47 
  48 static ssize_t enabled_store(struct device *dev, struct device_attribute *attr,
  49                              const char *buf, size_t n)
  50 {
  51         struct fieldbus_dev *fb = dev_get_drvdata(dev);
  52         bool value;
  53         int ret;
  54 
  55         if (!fb->simple_enable_set)
  56                 return -ENOTSUPP;
  57         ret = kstrtobool(buf, &value);
  58         if (ret)
  59                 return ret;
  60         ret = fb->simple_enable_set(fb, value);
  61         if (ret < 0)
  62                 return ret;
  63         return n;
  64 }
  65 static DEVICE_ATTR_RW(enabled);
  66 
  67 static ssize_t card_name_show(struct device *dev, struct device_attribute *attr,
  68                               char *buf)
  69 {
  70         struct fieldbus_dev *fb = dev_get_drvdata(dev);
  71 
  72         /*
  73          * card_name was provided by child driver, could potentially be long.
  74          * protect against buffer overrun.
  75          */
  76         return snprintf(buf, PAGE_SIZE, "%s\n", fb->card_name);
  77 }
  78 static DEVICE_ATTR_RO(card_name);
  79 
  80 static ssize_t read_area_size_show(struct device *dev,
  81                                    struct device_attribute *attr, char *buf)
  82 {
  83         struct fieldbus_dev *fb = dev_get_drvdata(dev);
  84 
  85         return sprintf(buf, "%zu\n", fb->read_area_sz);
  86 }
  87 static DEVICE_ATTR_RO(read_area_size);
  88 
  89 static ssize_t write_area_size_show(struct device *dev,
  90                                     struct device_attribute *attr, char *buf)
  91 {
  92         struct fieldbus_dev *fb = dev_get_drvdata(dev);
  93 
  94         return sprintf(buf, "%zu\n", fb->write_area_sz);
  95 }
  96 static DEVICE_ATTR_RO(write_area_size);
  97 
  98 static ssize_t fieldbus_id_show(struct device *dev,
  99                                 struct device_attribute *attr, char *buf)
 100 {
 101         struct fieldbus_dev *fb = dev_get_drvdata(dev);
 102 
 103         return fb->fieldbus_id_get(fb, buf, PAGE_SIZE);
 104 }
 105 static DEVICE_ATTR_RO(fieldbus_id);
 106 
 107 static ssize_t fieldbus_type_show(struct device *dev,
 108                                   struct device_attribute *attr, char *buf)
 109 {
 110         struct fieldbus_dev *fb = dev_get_drvdata(dev);
 111         const char *t;
 112 
 113         switch (fb->fieldbus_type) {
 114         case FIELDBUS_DEV_TYPE_PROFINET:
 115                 t = "profinet";
 116                 break;
 117         default:
 118                 t = "unknown";
 119                 break;
 120         }
 121 
 122         return sprintf(buf, "%s\n", t);
 123 }
 124 static DEVICE_ATTR_RO(fieldbus_type);
 125 
 126 static struct attribute *fieldbus_attrs[] = {
 127         &dev_attr_enabled.attr,
 128         &dev_attr_card_name.attr,
 129         &dev_attr_fieldbus_id.attr,
 130         &dev_attr_read_area_size.attr,
 131         &dev_attr_write_area_size.attr,
 132         &dev_attr_online.attr,
 133         &dev_attr_fieldbus_type.attr,
 134         NULL,
 135 };
 136 
 137 static umode_t fieldbus_is_visible(struct kobject *kobj, struct attribute *attr,
 138                                    int n)
 139 {
 140         struct device *dev = container_of(kobj, struct device, kobj);
 141         struct fieldbus_dev *fb = dev_get_drvdata(dev);
 142         umode_t mode = attr->mode;
 143 
 144         if (attr == &dev_attr_enabled.attr) {
 145                 mode = 0;
 146                 if (fb->enable_get)
 147                         mode |= 0444;
 148                 if (fb->simple_enable_set)
 149                         mode |= 0200;
 150         }
 151 
 152         return mode;
 153 }
 154 
 155 static const struct attribute_group fieldbus_group = {
 156         .attrs = fieldbus_attrs,
 157         .is_visible = fieldbus_is_visible,
 158 };
 159 __ATTRIBUTE_GROUPS(fieldbus);
 160 
 161 static struct class fieldbus_class = {
 162         .name =         "fieldbus_dev",
 163         .owner =        THIS_MODULE,
 164         .dev_groups =   fieldbus_groups,
 165 };
 166 
 167 struct fb_open_file {
 168         struct fieldbus_dev *fbdev;
 169         int dc_event;
 170 };
 171 
 172 static int fieldbus_open(struct inode *inode, struct file *filp)
 173 {
 174         struct fb_open_file *of;
 175         struct fieldbus_dev *fbdev = container_of(inode->i_cdev,
 176                                                 struct fieldbus_dev,
 177                                                 cdev);
 178 
 179         of = kzalloc(sizeof(*of), GFP_KERNEL);
 180         if (!of)
 181                 return -ENOMEM;
 182         of->fbdev = fbdev;
 183         filp->private_data = of;
 184         return 0;
 185 }
 186 
 187 static int fieldbus_release(struct inode *node, struct file *filp)
 188 {
 189         struct fb_open_file *of = filp->private_data;
 190 
 191         kfree(of);
 192         return 0;
 193 }
 194 
 195 static ssize_t fieldbus_read(struct file *filp, char __user *buf, size_t size,
 196                              loff_t *offset)
 197 {
 198         struct fb_open_file *of = filp->private_data;
 199         struct fieldbus_dev *fbdev = of->fbdev;
 200 
 201         of->dc_event = fbdev->dc_event;
 202         return fbdev->read_area(fbdev, buf, size, offset);
 203 }
 204 
 205 static ssize_t fieldbus_write(struct file *filp, const char __user *buf,
 206                               size_t size, loff_t *offset)
 207 {
 208         struct fb_open_file *of = filp->private_data;
 209         struct fieldbus_dev *fbdev = of->fbdev;
 210 
 211         return fbdev->write_area(fbdev, buf, size, offset);
 212 }
 213 
 214 static __poll_t fieldbus_poll(struct file *filp, poll_table *wait)
 215 {
 216         struct fb_open_file *of = filp->private_data;
 217         struct fieldbus_dev *fbdev = of->fbdev;
 218         __poll_t mask = EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM;
 219 
 220         poll_wait(filp, &fbdev->dc_wq, wait);
 221         /* data changed ? */
 222         if (fbdev->dc_event != of->dc_event)
 223                 mask |= EPOLLPRI | EPOLLERR;
 224         return mask;
 225 }
 226 
 227 static const struct file_operations fieldbus_fops = {
 228         .open           = fieldbus_open,
 229         .release        = fieldbus_release,
 230         .read           = fieldbus_read,
 231         .write          = fieldbus_write,
 232         .poll           = fieldbus_poll,
 233         .llseek         = generic_file_llseek,
 234         .owner          = THIS_MODULE,
 235 };
 236 
 237 void fieldbus_dev_area_updated(struct fieldbus_dev *fb)
 238 {
 239         fb->dc_event++;
 240         wake_up_all(&fb->dc_wq);
 241 }
 242 EXPORT_SYMBOL_GPL(fieldbus_dev_area_updated);
 243 
 244 void fieldbus_dev_online_changed(struct fieldbus_dev *fb, bool online)
 245 {
 246         fb->online = online;
 247         kobject_uevent(&fb->dev->kobj, KOBJ_CHANGE);
 248 }
 249 EXPORT_SYMBOL_GPL(fieldbus_dev_online_changed);
 250 
 251 static void __fieldbus_dev_unregister(struct fieldbus_dev *fb)
 252 {
 253         if (!fb)
 254                 return;
 255         device_destroy(&fieldbus_class, fb->cdev.dev);
 256         cdev_del(&fb->cdev);
 257         ida_simple_remove(&fieldbus_ida, fb->id);
 258 }
 259 
 260 void fieldbus_dev_unregister(struct fieldbus_dev *fb)
 261 {
 262         mutex_lock(&fieldbus_mtx);
 263         __fieldbus_dev_unregister(fb);
 264         mutex_unlock(&fieldbus_mtx);
 265 }
 266 EXPORT_SYMBOL_GPL(fieldbus_dev_unregister);
 267 
 268 static int __fieldbus_dev_register(struct fieldbus_dev *fb)
 269 {
 270         dev_t devno;
 271         int err;
 272 
 273         if (!fb)
 274                 return -EINVAL;
 275         if (!fb->read_area || !fb->write_area || !fb->fieldbus_id_get)
 276                 return -EINVAL;
 277         fb->id = ida_simple_get(&fieldbus_ida, 0, MAX_FIELDBUSES, GFP_KERNEL);
 278         if (fb->id < 0)
 279                 return fb->id;
 280         devno = MKDEV(MAJOR(fieldbus_devt), fb->id);
 281         init_waitqueue_head(&fb->dc_wq);
 282         cdev_init(&fb->cdev, &fieldbus_fops);
 283         err = cdev_add(&fb->cdev, devno, 1);
 284         if (err) {
 285                 pr_err("fieldbus_dev%d unable to add device %d:%d\n",
 286                        fb->id, MAJOR(fieldbus_devt), fb->id);
 287                 goto err_cdev;
 288         }
 289         fb->dev = device_create(&fieldbus_class, fb->parent, devno, fb,
 290                                 "fieldbus_dev%d", fb->id);
 291         if (IS_ERR(fb->dev)) {
 292                 err = PTR_ERR(fb->dev);
 293                 goto err_dev_create;
 294         }
 295         return 0;
 296 
 297 err_dev_create:
 298         cdev_del(&fb->cdev);
 299 err_cdev:
 300         ida_simple_remove(&fieldbus_ida, fb->id);
 301         return err;
 302 }
 303 
 304 int fieldbus_dev_register(struct fieldbus_dev *fb)
 305 {
 306         int err;
 307 
 308         mutex_lock(&fieldbus_mtx);
 309         err = __fieldbus_dev_register(fb);
 310         mutex_unlock(&fieldbus_mtx);
 311 
 312         return err;
 313 }
 314 EXPORT_SYMBOL_GPL(fieldbus_dev_register);
 315 
 316 static int __init fieldbus_init(void)
 317 {
 318         int err;
 319 
 320         err = class_register(&fieldbus_class);
 321         if (err < 0) {
 322                 pr_err("fieldbus_dev: could not register class\n");
 323                 return err;
 324         }
 325         err = alloc_chrdev_region(&fieldbus_devt, 0,
 326                                   MAX_FIELDBUSES, "fieldbus_dev");
 327         if (err < 0) {
 328                 pr_err("fieldbus_dev: unable to allocate char dev region\n");
 329                 goto err_alloc;
 330         }
 331         return 0;
 332 
 333 err_alloc:
 334         class_unregister(&fieldbus_class);
 335         return err;
 336 }
 337 
 338 static void __exit fieldbus_exit(void)
 339 {
 340         unregister_chrdev_region(fieldbus_devt, MAX_FIELDBUSES);
 341         class_unregister(&fieldbus_class);
 342         ida_destroy(&fieldbus_ida);
 343 }
 344 
 345 subsys_initcall(fieldbus_init);
 346 module_exit(fieldbus_exit);
 347 
 348 MODULE_AUTHOR("Sven Van Asbroeck <TheSven73@gmail.com>");
 349 MODULE_AUTHOR("Jonathan Stiles <jonathans@arcx.com>");
 350 MODULE_DESCRIPTION("Fieldbus Device Driver Core");
 351 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */