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