0001
0002
0003
0004
0005
0006 #include <linux/cdev.h>
0007 #include <linux/counter.h>
0008 #include <linux/device.h>
0009 #include <linux/device/bus.h>
0010 #include <linux/export.h>
0011 #include <linux/fs.h>
0012 #include <linux/gfp.h>
0013 #include <linux/idr.h>
0014 #include <linux/init.h>
0015 #include <linux/kdev_t.h>
0016 #include <linux/module.h>
0017 #include <linux/mutex.h>
0018 #include <linux/slab.h>
0019 #include <linux/types.h>
0020 #include <linux/wait.h>
0021
0022 #include "counter-chrdev.h"
0023 #include "counter-sysfs.h"
0024
0025 #define COUNTER_NAME "counter"
0026
0027
0028 static DEFINE_IDA(counter_ida);
0029
0030 struct counter_device_allochelper {
0031 struct counter_device counter;
0032
0033
0034
0035
0036
0037 unsigned long privdata[] ____cacheline_aligned;
0038 };
0039
0040 static void counter_device_release(struct device *dev)
0041 {
0042 struct counter_device *const counter =
0043 container_of(dev, struct counter_device, dev);
0044
0045 counter_chrdev_remove(counter);
0046 ida_free(&counter_ida, dev->id);
0047
0048 kfree(container_of(counter, struct counter_device_allochelper, counter));
0049 }
0050
0051 static struct device_type counter_device_type = {
0052 .name = "counter_device",
0053 .release = counter_device_release,
0054 };
0055
0056 static struct bus_type counter_bus_type = {
0057 .name = "counter",
0058 .dev_name = "counter",
0059 };
0060
0061 static dev_t counter_devt;
0062
0063
0064
0065
0066
0067
0068
0069 void *counter_priv(const struct counter_device *const counter)
0070 {
0071 struct counter_device_allochelper *ch =
0072 container_of(counter, struct counter_device_allochelper, counter);
0073
0074 return &ch->privdata;
0075 }
0076 EXPORT_SYMBOL_GPL(counter_priv);
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087 struct counter_device *counter_alloc(size_t sizeof_priv)
0088 {
0089 struct counter_device_allochelper *ch;
0090 struct counter_device *counter;
0091 struct device *dev;
0092 int err;
0093
0094 ch = kzalloc(sizeof(*ch) + sizeof_priv, GFP_KERNEL);
0095 if (!ch)
0096 return NULL;
0097
0098 counter = &ch->counter;
0099 dev = &counter->dev;
0100
0101
0102 err = ida_alloc(&counter_ida, GFP_KERNEL);
0103 if (err < 0)
0104 goto err_ida_alloc;
0105 dev->id = err;
0106
0107 mutex_init(&counter->ops_exist_lock);
0108 dev->type = &counter_device_type;
0109 dev->bus = &counter_bus_type;
0110 dev->devt = MKDEV(MAJOR(counter_devt), dev->id);
0111
0112 err = counter_chrdev_add(counter);
0113 if (err < 0)
0114 goto err_chrdev_add;
0115
0116 device_initialize(dev);
0117
0118 err = dev_set_name(dev, COUNTER_NAME "%d", dev->id);
0119 if (err)
0120 goto err_dev_set_name;
0121
0122 return counter;
0123
0124 err_dev_set_name:
0125
0126 counter_chrdev_remove(counter);
0127 err_chrdev_add:
0128
0129 ida_free(&counter_ida, dev->id);
0130 err_ida_alloc:
0131
0132 kfree(ch);
0133
0134 return NULL;
0135 }
0136 EXPORT_SYMBOL_GPL(counter_alloc);
0137
0138 void counter_put(struct counter_device *counter)
0139 {
0140 put_device(&counter->dev);
0141 }
0142 EXPORT_SYMBOL_GPL(counter_put);
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152 int counter_add(struct counter_device *counter)
0153 {
0154 int err;
0155 struct device *dev = &counter->dev;
0156
0157 if (counter->parent) {
0158 dev->parent = counter->parent;
0159 dev->of_node = counter->parent->of_node;
0160 }
0161
0162 err = counter_sysfs_add(counter);
0163 if (err < 0)
0164 return err;
0165
0166
0167 return cdev_device_add(&counter->chrdev, dev);
0168 }
0169 EXPORT_SYMBOL_GPL(counter_add);
0170
0171
0172
0173
0174
0175
0176
0177 void counter_unregister(struct counter_device *const counter)
0178 {
0179 if (!counter)
0180 return;
0181
0182 cdev_device_del(&counter->chrdev, &counter->dev);
0183
0184 mutex_lock(&counter->ops_exist_lock);
0185
0186 counter->ops = NULL;
0187 wake_up(&counter->events_wait);
0188
0189 mutex_unlock(&counter->ops_exist_lock);
0190 }
0191 EXPORT_SYMBOL_GPL(counter_unregister);
0192
0193 static void devm_counter_release(void *counter)
0194 {
0195 counter_unregister(counter);
0196 }
0197
0198 static void devm_counter_put(void *counter)
0199 {
0200 counter_put(counter);
0201 }
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211 struct counter_device *devm_counter_alloc(struct device *dev, size_t sizeof_priv)
0212 {
0213 struct counter_device *counter;
0214 int err;
0215
0216 counter = counter_alloc(sizeof_priv);
0217 if (!counter)
0218 return NULL;
0219
0220 err = devm_add_action_or_reset(dev, devm_counter_put, counter);
0221 if (err < 0)
0222 return NULL;
0223
0224 return counter;
0225 }
0226 EXPORT_SYMBOL_GPL(devm_counter_alloc);
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236 int devm_counter_add(struct device *dev,
0237 struct counter_device *const counter)
0238 {
0239 int err;
0240
0241 err = counter_add(counter);
0242 if (err < 0)
0243 return err;
0244
0245 return devm_add_action_or_reset(dev, devm_counter_release, counter);
0246 }
0247 EXPORT_SYMBOL_GPL(devm_counter_add);
0248
0249 #define COUNTER_DEV_MAX 256
0250
0251 static int __init counter_init(void)
0252 {
0253 int err;
0254
0255 err = bus_register(&counter_bus_type);
0256 if (err < 0)
0257 return err;
0258
0259 err = alloc_chrdev_region(&counter_devt, 0, COUNTER_DEV_MAX,
0260 COUNTER_NAME);
0261 if (err < 0)
0262 goto err_unregister_bus;
0263
0264 return 0;
0265
0266 err_unregister_bus:
0267 bus_unregister(&counter_bus_type);
0268 return err;
0269 }
0270
0271 static void __exit counter_exit(void)
0272 {
0273 unregister_chrdev_region(counter_devt, COUNTER_DEV_MAX);
0274 bus_unregister(&counter_bus_type);
0275 }
0276
0277 subsys_initcall(counter_init);
0278 module_exit(counter_exit);
0279
0280 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
0281 MODULE_DESCRIPTION("Generic Counter interface");
0282 MODULE_LICENSE("GPL v2");