xref: /linux/drivers/staging/fieldbus/dev_core.c (revision dd093fb0)
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