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