0001
0002
0003
0004
0005
0006 #include <linux/counter.h>
0007 #include <linux/device.h>
0008 #include <linux/err.h>
0009 #include <linux/gfp.h>
0010 #include <linux/kernel.h>
0011 #include <linux/kfifo.h>
0012 #include <linux/kstrtox.h>
0013 #include <linux/list.h>
0014 #include <linux/mutex.h>
0015 #include <linux/spinlock.h>
0016 #include <linux/string.h>
0017 #include <linux/sysfs.h>
0018 #include <linux/types.h>
0019
0020 #include "counter-sysfs.h"
0021
0022 static inline struct counter_device *counter_from_dev(struct device *dev)
0023 {
0024 return container_of(dev, struct counter_device, dev);
0025 }
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 struct counter_attribute {
0036 struct device_attribute dev_attr;
0037 struct list_head l;
0038
0039 struct counter_comp comp;
0040 enum counter_scope scope;
0041 void *parent;
0042 };
0043
0044 #define to_counter_attribute(_dev_attr) \
0045 container_of(_dev_attr, struct counter_attribute, dev_attr)
0046
0047
0048
0049
0050
0051
0052
0053 struct counter_attribute_group {
0054 const char *name;
0055 struct list_head attr_list;
0056 size_t num_attr;
0057 };
0058
0059 static const char *const counter_function_str[] = {
0060 [COUNTER_FUNCTION_INCREASE] = "increase",
0061 [COUNTER_FUNCTION_DECREASE] = "decrease",
0062 [COUNTER_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
0063 [COUNTER_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a",
0064 [COUNTER_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b",
0065 [COUNTER_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a",
0066 [COUNTER_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b",
0067 [COUNTER_FUNCTION_QUADRATURE_X4] = "quadrature x4"
0068 };
0069
0070 static const char *const counter_signal_value_str[] = {
0071 [COUNTER_SIGNAL_LEVEL_LOW] = "low",
0072 [COUNTER_SIGNAL_LEVEL_HIGH] = "high"
0073 };
0074
0075 static const char *const counter_synapse_action_str[] = {
0076 [COUNTER_SYNAPSE_ACTION_NONE] = "none",
0077 [COUNTER_SYNAPSE_ACTION_RISING_EDGE] = "rising edge",
0078 [COUNTER_SYNAPSE_ACTION_FALLING_EDGE] = "falling edge",
0079 [COUNTER_SYNAPSE_ACTION_BOTH_EDGES] = "both edges"
0080 };
0081
0082 static const char *const counter_count_direction_str[] = {
0083 [COUNTER_COUNT_DIRECTION_FORWARD] = "forward",
0084 [COUNTER_COUNT_DIRECTION_BACKWARD] = "backward"
0085 };
0086
0087 static const char *const counter_count_mode_str[] = {
0088 [COUNTER_COUNT_MODE_NORMAL] = "normal",
0089 [COUNTER_COUNT_MODE_RANGE_LIMIT] = "range limit",
0090 [COUNTER_COUNT_MODE_NON_RECYCLE] = "non-recycle",
0091 [COUNTER_COUNT_MODE_MODULO_N] = "modulo-n"
0092 };
0093
0094 static ssize_t counter_comp_u8_show(struct device *dev,
0095 struct device_attribute *attr, char *buf)
0096 {
0097 const struct counter_attribute *const a = to_counter_attribute(attr);
0098 struct counter_device *const counter = counter_from_dev(dev);
0099 int err;
0100 u8 data = 0;
0101
0102 switch (a->scope) {
0103 case COUNTER_SCOPE_DEVICE:
0104 err = a->comp.device_u8_read(counter, &data);
0105 break;
0106 case COUNTER_SCOPE_SIGNAL:
0107 err = a->comp.signal_u8_read(counter, a->parent, &data);
0108 break;
0109 case COUNTER_SCOPE_COUNT:
0110 err = a->comp.count_u8_read(counter, a->parent, &data);
0111 break;
0112 default:
0113 return -EINVAL;
0114 }
0115 if (err < 0)
0116 return err;
0117
0118 if (a->comp.type == COUNTER_COMP_BOOL)
0119
0120 data = !!data;
0121
0122 return sysfs_emit(buf, "%u\n", (unsigned int)data);
0123 }
0124
0125 static ssize_t counter_comp_u8_store(struct device *dev,
0126 struct device_attribute *attr,
0127 const char *buf, size_t len)
0128 {
0129 const struct counter_attribute *const a = to_counter_attribute(attr);
0130 struct counter_device *const counter = counter_from_dev(dev);
0131 int err;
0132 bool bool_data = 0;
0133 u8 data = 0;
0134
0135 if (a->comp.type == COUNTER_COMP_BOOL) {
0136 err = kstrtobool(buf, &bool_data);
0137 data = bool_data;
0138 } else
0139 err = kstrtou8(buf, 0, &data);
0140 if (err < 0)
0141 return err;
0142
0143 switch (a->scope) {
0144 case COUNTER_SCOPE_DEVICE:
0145 err = a->comp.device_u8_write(counter, data);
0146 break;
0147 case COUNTER_SCOPE_SIGNAL:
0148 err = a->comp.signal_u8_write(counter, a->parent, data);
0149 break;
0150 case COUNTER_SCOPE_COUNT:
0151 err = a->comp.count_u8_write(counter, a->parent, data);
0152 break;
0153 default:
0154 return -EINVAL;
0155 }
0156 if (err < 0)
0157 return err;
0158
0159 return len;
0160 }
0161
0162 static ssize_t counter_comp_u32_show(struct device *dev,
0163 struct device_attribute *attr, char *buf)
0164 {
0165 const struct counter_attribute *const a = to_counter_attribute(attr);
0166 struct counter_device *const counter = counter_from_dev(dev);
0167 const struct counter_available *const avail = a->comp.priv;
0168 int err;
0169 u32 data = 0;
0170
0171 switch (a->scope) {
0172 case COUNTER_SCOPE_DEVICE:
0173 err = a->comp.device_u32_read(counter, &data);
0174 break;
0175 case COUNTER_SCOPE_SIGNAL:
0176 err = a->comp.signal_u32_read(counter, a->parent, &data);
0177 break;
0178 case COUNTER_SCOPE_COUNT:
0179 if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
0180 err = a->comp.action_read(counter, a->parent,
0181 a->comp.priv, &data);
0182 else
0183 err = a->comp.count_u32_read(counter, a->parent, &data);
0184 break;
0185 default:
0186 return -EINVAL;
0187 }
0188 if (err < 0)
0189 return err;
0190
0191 switch (a->comp.type) {
0192 case COUNTER_COMP_FUNCTION:
0193 return sysfs_emit(buf, "%s\n", counter_function_str[data]);
0194 case COUNTER_COMP_SIGNAL_LEVEL:
0195 return sysfs_emit(buf, "%s\n", counter_signal_value_str[data]);
0196 case COUNTER_COMP_SYNAPSE_ACTION:
0197 return sysfs_emit(buf, "%s\n", counter_synapse_action_str[data]);
0198 case COUNTER_COMP_ENUM:
0199 return sysfs_emit(buf, "%s\n", avail->strs[data]);
0200 case COUNTER_COMP_COUNT_DIRECTION:
0201 return sysfs_emit(buf, "%s\n", counter_count_direction_str[data]);
0202 case COUNTER_COMP_COUNT_MODE:
0203 return sysfs_emit(buf, "%s\n", counter_count_mode_str[data]);
0204 default:
0205 return sysfs_emit(buf, "%u\n", (unsigned int)data);
0206 }
0207 }
0208
0209 static int counter_find_enum(u32 *const enum_item, const u32 *const enums,
0210 const size_t num_enums, const char *const buf,
0211 const char *const string_array[])
0212 {
0213 size_t index;
0214
0215 for (index = 0; index < num_enums; index++) {
0216 *enum_item = enums[index];
0217 if (sysfs_streq(buf, string_array[*enum_item]))
0218 return 0;
0219 }
0220
0221 return -EINVAL;
0222 }
0223
0224 static ssize_t counter_comp_u32_store(struct device *dev,
0225 struct device_attribute *attr,
0226 const char *buf, size_t len)
0227 {
0228 const struct counter_attribute *const a = to_counter_attribute(attr);
0229 struct counter_device *const counter = counter_from_dev(dev);
0230 struct counter_count *const count = a->parent;
0231 struct counter_synapse *const synapse = a->comp.priv;
0232 const struct counter_available *const avail = a->comp.priv;
0233 int err;
0234 u32 data = 0;
0235
0236 switch (a->comp.type) {
0237 case COUNTER_COMP_FUNCTION:
0238 err = counter_find_enum(&data, count->functions_list,
0239 count->num_functions, buf,
0240 counter_function_str);
0241 break;
0242 case COUNTER_COMP_SYNAPSE_ACTION:
0243 err = counter_find_enum(&data, synapse->actions_list,
0244 synapse->num_actions, buf,
0245 counter_synapse_action_str);
0246 break;
0247 case COUNTER_COMP_ENUM:
0248 err = __sysfs_match_string(avail->strs, avail->num_items, buf);
0249 data = err;
0250 break;
0251 case COUNTER_COMP_COUNT_MODE:
0252 err = counter_find_enum(&data, avail->enums, avail->num_items,
0253 buf, counter_count_mode_str);
0254 break;
0255 default:
0256 err = kstrtou32(buf, 0, &data);
0257 break;
0258 }
0259 if (err < 0)
0260 return err;
0261
0262 switch (a->scope) {
0263 case COUNTER_SCOPE_DEVICE:
0264 err = a->comp.device_u32_write(counter, data);
0265 break;
0266 case COUNTER_SCOPE_SIGNAL:
0267 err = a->comp.signal_u32_write(counter, a->parent, data);
0268 break;
0269 case COUNTER_SCOPE_COUNT:
0270 if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
0271 err = a->comp.action_write(counter, count, synapse,
0272 data);
0273 else
0274 err = a->comp.count_u32_write(counter, count, data);
0275 break;
0276 default:
0277 return -EINVAL;
0278 }
0279 if (err < 0)
0280 return err;
0281
0282 return len;
0283 }
0284
0285 static ssize_t counter_comp_u64_show(struct device *dev,
0286 struct device_attribute *attr, char *buf)
0287 {
0288 const struct counter_attribute *const a = to_counter_attribute(attr);
0289 struct counter_device *const counter = counter_from_dev(dev);
0290 int err;
0291 u64 data = 0;
0292
0293 switch (a->scope) {
0294 case COUNTER_SCOPE_DEVICE:
0295 err = a->comp.device_u64_read(counter, &data);
0296 break;
0297 case COUNTER_SCOPE_SIGNAL:
0298 err = a->comp.signal_u64_read(counter, a->parent, &data);
0299 break;
0300 case COUNTER_SCOPE_COUNT:
0301 err = a->comp.count_u64_read(counter, a->parent, &data);
0302 break;
0303 default:
0304 return -EINVAL;
0305 }
0306 if (err < 0)
0307 return err;
0308
0309 return sysfs_emit(buf, "%llu\n", (unsigned long long)data);
0310 }
0311
0312 static ssize_t counter_comp_u64_store(struct device *dev,
0313 struct device_attribute *attr,
0314 const char *buf, size_t len)
0315 {
0316 const struct counter_attribute *const a = to_counter_attribute(attr);
0317 struct counter_device *const counter = counter_from_dev(dev);
0318 int err;
0319 u64 data = 0;
0320
0321 err = kstrtou64(buf, 0, &data);
0322 if (err < 0)
0323 return err;
0324
0325 switch (a->scope) {
0326 case COUNTER_SCOPE_DEVICE:
0327 err = a->comp.device_u64_write(counter, data);
0328 break;
0329 case COUNTER_SCOPE_SIGNAL:
0330 err = a->comp.signal_u64_write(counter, a->parent, data);
0331 break;
0332 case COUNTER_SCOPE_COUNT:
0333 err = a->comp.count_u64_write(counter, a->parent, data);
0334 break;
0335 default:
0336 return -EINVAL;
0337 }
0338 if (err < 0)
0339 return err;
0340
0341 return len;
0342 }
0343
0344 static ssize_t enums_available_show(const u32 *const enums,
0345 const size_t num_enums,
0346 const char *const strs[], char *buf)
0347 {
0348 size_t len = 0;
0349 size_t index;
0350
0351 for (index = 0; index < num_enums; index++)
0352 len += sysfs_emit_at(buf, len, "%s\n", strs[enums[index]]);
0353
0354 return len;
0355 }
0356
0357 static ssize_t strs_available_show(const struct counter_available *const avail,
0358 char *buf)
0359 {
0360 size_t len = 0;
0361 size_t index;
0362
0363 for (index = 0; index < avail->num_items; index++)
0364 len += sysfs_emit_at(buf, len, "%s\n", avail->strs[index]);
0365
0366 return len;
0367 }
0368
0369 static ssize_t counter_comp_available_show(struct device *dev,
0370 struct device_attribute *attr,
0371 char *buf)
0372 {
0373 const struct counter_attribute *const a = to_counter_attribute(attr);
0374 const struct counter_count *const count = a->parent;
0375 const struct counter_synapse *const synapse = a->comp.priv;
0376 const struct counter_available *const avail = a->comp.priv;
0377
0378 switch (a->comp.type) {
0379 case COUNTER_COMP_FUNCTION:
0380 return enums_available_show(count->functions_list,
0381 count->num_functions,
0382 counter_function_str, buf);
0383 case COUNTER_COMP_SYNAPSE_ACTION:
0384 return enums_available_show(synapse->actions_list,
0385 synapse->num_actions,
0386 counter_synapse_action_str, buf);
0387 case COUNTER_COMP_ENUM:
0388 return strs_available_show(avail, buf);
0389 case COUNTER_COMP_COUNT_MODE:
0390 return enums_available_show(avail->enums, avail->num_items,
0391 counter_count_mode_str, buf);
0392 default:
0393 return -EINVAL;
0394 }
0395 }
0396
0397 static int counter_avail_attr_create(struct device *const dev,
0398 struct counter_attribute_group *const group,
0399 const struct counter_comp *const comp, void *const parent)
0400 {
0401 struct counter_attribute *counter_attr;
0402 struct device_attribute *dev_attr;
0403
0404 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
0405 if (!counter_attr)
0406 return -ENOMEM;
0407
0408
0409 counter_attr->comp.type = comp->type;
0410 counter_attr->comp.priv = comp->priv;
0411 counter_attr->parent = parent;
0412
0413
0414 dev_attr = &counter_attr->dev_attr;
0415 sysfs_attr_init(&dev_attr->attr);
0416
0417
0418 dev_attr->attr.name = devm_kasprintf(dev, GFP_KERNEL, "%s_available",
0419 comp->name);
0420 if (!dev_attr->attr.name)
0421 return -ENOMEM;
0422 dev_attr->attr.mode = 0444;
0423 dev_attr->show = counter_comp_available_show;
0424
0425
0426 list_add(&counter_attr->l, &group->attr_list);
0427 group->num_attr++;
0428
0429 return 0;
0430 }
0431
0432 static int counter_attr_create(struct device *const dev,
0433 struct counter_attribute_group *const group,
0434 const struct counter_comp *const comp,
0435 const enum counter_scope scope,
0436 void *const parent)
0437 {
0438 struct counter_attribute *counter_attr;
0439 struct device_attribute *dev_attr;
0440
0441 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
0442 if (!counter_attr)
0443 return -ENOMEM;
0444
0445
0446 counter_attr->comp = *comp;
0447 counter_attr->scope = scope;
0448 counter_attr->parent = parent;
0449
0450
0451 dev_attr = &counter_attr->dev_attr;
0452 sysfs_attr_init(&dev_attr->attr);
0453 dev_attr->attr.name = comp->name;
0454 switch (comp->type) {
0455 case COUNTER_COMP_U8:
0456 case COUNTER_COMP_BOOL:
0457 if (comp->device_u8_read) {
0458 dev_attr->attr.mode |= 0444;
0459 dev_attr->show = counter_comp_u8_show;
0460 }
0461 if (comp->device_u8_write) {
0462 dev_attr->attr.mode |= 0200;
0463 dev_attr->store = counter_comp_u8_store;
0464 }
0465 break;
0466 case COUNTER_COMP_SIGNAL_LEVEL:
0467 case COUNTER_COMP_FUNCTION:
0468 case COUNTER_COMP_SYNAPSE_ACTION:
0469 case COUNTER_COMP_ENUM:
0470 case COUNTER_COMP_COUNT_DIRECTION:
0471 case COUNTER_COMP_COUNT_MODE:
0472 if (comp->device_u32_read) {
0473 dev_attr->attr.mode |= 0444;
0474 dev_attr->show = counter_comp_u32_show;
0475 }
0476 if (comp->device_u32_write) {
0477 dev_attr->attr.mode |= 0200;
0478 dev_attr->store = counter_comp_u32_store;
0479 }
0480 break;
0481 case COUNTER_COMP_U64:
0482 if (comp->device_u64_read) {
0483 dev_attr->attr.mode |= 0444;
0484 dev_attr->show = counter_comp_u64_show;
0485 }
0486 if (comp->device_u64_write) {
0487 dev_attr->attr.mode |= 0200;
0488 dev_attr->store = counter_comp_u64_store;
0489 }
0490 break;
0491 default:
0492 return -EINVAL;
0493 }
0494
0495
0496 list_add(&counter_attr->l, &group->attr_list);
0497 group->num_attr++;
0498
0499
0500 switch (comp->type) {
0501 case COUNTER_COMP_FUNCTION:
0502 case COUNTER_COMP_SYNAPSE_ACTION:
0503 case COUNTER_COMP_ENUM:
0504 case COUNTER_COMP_COUNT_MODE:
0505 return counter_avail_attr_create(dev, group, comp, parent);
0506 default:
0507 return 0;
0508 }
0509 }
0510
0511 static ssize_t counter_comp_name_show(struct device *dev,
0512 struct device_attribute *attr, char *buf)
0513 {
0514 return sysfs_emit(buf, "%s\n", to_counter_attribute(attr)->comp.name);
0515 }
0516
0517 static int counter_name_attr_create(struct device *const dev,
0518 struct counter_attribute_group *const group,
0519 const char *const name)
0520 {
0521 struct counter_attribute *counter_attr;
0522
0523 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
0524 if (!counter_attr)
0525 return -ENOMEM;
0526
0527
0528 counter_attr->comp.name = name;
0529
0530
0531 sysfs_attr_init(&counter_attr->dev_attr.attr);
0532 counter_attr->dev_attr.attr.name = "name";
0533 counter_attr->dev_attr.attr.mode = 0444;
0534 counter_attr->dev_attr.show = counter_comp_name_show;
0535
0536
0537 list_add(&counter_attr->l, &group->attr_list);
0538 group->num_attr++;
0539
0540 return 0;
0541 }
0542
0543 static ssize_t counter_comp_id_show(struct device *dev,
0544 struct device_attribute *attr, char *buf)
0545 {
0546 const size_t id = (size_t)to_counter_attribute(attr)->comp.priv;
0547
0548 return sysfs_emit(buf, "%zu\n", id);
0549 }
0550
0551 static int counter_comp_id_attr_create(struct device *const dev,
0552 struct counter_attribute_group *const group,
0553 const char *name, const size_t id)
0554 {
0555 struct counter_attribute *counter_attr;
0556
0557
0558 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
0559 if (!counter_attr)
0560 return -ENOMEM;
0561
0562
0563 name = devm_kasprintf(dev, GFP_KERNEL, "%s_component_id", name);
0564 if (!name)
0565 return -ENOMEM;
0566
0567
0568 counter_attr->comp.priv = (void *)id;
0569
0570
0571 sysfs_attr_init(&counter_attr->dev_attr.attr);
0572 counter_attr->dev_attr.attr.name = name;
0573 counter_attr->dev_attr.attr.mode = 0444;
0574 counter_attr->dev_attr.show = counter_comp_id_show;
0575
0576
0577 list_add(&counter_attr->l, &group->attr_list);
0578 group->num_attr++;
0579
0580 return 0;
0581 }
0582
0583 static struct counter_comp counter_signal_comp = {
0584 .type = COUNTER_COMP_SIGNAL_LEVEL,
0585 .name = "signal",
0586 };
0587
0588 static int counter_signal_attrs_create(struct counter_device *const counter,
0589 struct counter_attribute_group *const cattr_group,
0590 struct counter_signal *const signal)
0591 {
0592 const enum counter_scope scope = COUNTER_SCOPE_SIGNAL;
0593 struct device *const dev = &counter->dev;
0594 int err;
0595 struct counter_comp comp;
0596 size_t i;
0597 struct counter_comp *ext;
0598
0599
0600 comp = counter_signal_comp;
0601 comp.signal_u32_read = counter->ops->signal_read;
0602 err = counter_attr_create(dev, cattr_group, &comp, scope, signal);
0603 if (err < 0)
0604 return err;
0605
0606
0607 err = counter_name_attr_create(dev, cattr_group, signal->name);
0608 if (err < 0)
0609 return err;
0610
0611
0612 for (i = 0; i < signal->num_ext; i++) {
0613 ext = &signal->ext[i];
0614
0615 err = counter_attr_create(dev, cattr_group, ext, scope, signal);
0616 if (err < 0)
0617 return err;
0618
0619 err = counter_comp_id_attr_create(dev, cattr_group, ext->name,
0620 i);
0621 if (err < 0)
0622 return err;
0623 }
0624
0625 return 0;
0626 }
0627
0628 static int counter_sysfs_signals_add(struct counter_device *const counter,
0629 struct counter_attribute_group *const groups)
0630 {
0631 size_t i;
0632 int err;
0633
0634
0635 for (i = 0; i < counter->num_signals; i++) {
0636
0637 groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
0638 "signal%zu", i);
0639 if (!groups[i].name)
0640 return -ENOMEM;
0641
0642
0643 err = counter_signal_attrs_create(counter, groups + i,
0644 counter->signals + i);
0645 if (err < 0)
0646 return err;
0647 }
0648
0649 return 0;
0650 }
0651
0652 static int counter_sysfs_synapses_add(struct counter_device *const counter,
0653 struct counter_attribute_group *const group,
0654 struct counter_count *const count)
0655 {
0656 size_t i;
0657
0658
0659 for (i = 0; i < count->num_synapses; i++) {
0660 struct device *const dev = &counter->dev;
0661 struct counter_synapse *synapse;
0662 size_t id;
0663 struct counter_comp comp;
0664 int err;
0665
0666 synapse = count->synapses + i;
0667
0668
0669 id = synapse->signal - counter->signals;
0670 comp.name = devm_kasprintf(dev, GFP_KERNEL, "signal%zu_action",
0671 id);
0672 if (!comp.name)
0673 return -ENOMEM;
0674
0675
0676 comp.type = COUNTER_COMP_SYNAPSE_ACTION;
0677 comp.action_read = counter->ops->action_read;
0678 comp.action_write = counter->ops->action_write;
0679 comp.priv = synapse;
0680 err = counter_attr_create(dev, group, &comp,
0681 COUNTER_SCOPE_COUNT, count);
0682 if (err < 0)
0683 return err;
0684
0685
0686 err = counter_comp_id_attr_create(dev, group, comp.name, i);
0687 if (err < 0)
0688 return err;
0689 }
0690
0691 return 0;
0692 }
0693
0694 static struct counter_comp counter_count_comp =
0695 COUNTER_COMP_COUNT_U64("count", NULL, NULL);
0696
0697 static struct counter_comp counter_function_comp = {
0698 .type = COUNTER_COMP_FUNCTION,
0699 .name = "function",
0700 };
0701
0702 static int counter_count_attrs_create(struct counter_device *const counter,
0703 struct counter_attribute_group *const cattr_group,
0704 struct counter_count *const count)
0705 {
0706 const enum counter_scope scope = COUNTER_SCOPE_COUNT;
0707 struct device *const dev = &counter->dev;
0708 int err;
0709 struct counter_comp comp;
0710 size_t i;
0711 struct counter_comp *ext;
0712
0713
0714 comp = counter_count_comp;
0715 comp.count_u64_read = counter->ops->count_read;
0716 comp.count_u64_write = counter->ops->count_write;
0717 err = counter_attr_create(dev, cattr_group, &comp, scope, count);
0718 if (err < 0)
0719 return err;
0720
0721
0722 err = counter_name_attr_create(dev, cattr_group, count->name);
0723 if (err < 0)
0724 return err;
0725
0726
0727 comp = counter_function_comp;
0728 comp.count_u32_read = counter->ops->function_read;
0729 comp.count_u32_write = counter->ops->function_write;
0730 err = counter_attr_create(dev, cattr_group, &comp, scope, count);
0731 if (err < 0)
0732 return err;
0733
0734
0735 for (i = 0; i < count->num_ext; i++) {
0736 ext = &count->ext[i];
0737
0738 err = counter_attr_create(dev, cattr_group, ext, scope, count);
0739 if (err < 0)
0740 return err;
0741
0742 err = counter_comp_id_attr_create(dev, cattr_group, ext->name,
0743 i);
0744 if (err < 0)
0745 return err;
0746 }
0747
0748 return 0;
0749 }
0750
0751 static int counter_sysfs_counts_add(struct counter_device *const counter,
0752 struct counter_attribute_group *const groups)
0753 {
0754 size_t i;
0755 struct counter_count *count;
0756 int err;
0757
0758
0759 for (i = 0; i < counter->num_counts; i++) {
0760 count = counter->counts + i;
0761
0762
0763 groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
0764 "count%zu", i);
0765 if (!groups[i].name)
0766 return -ENOMEM;
0767
0768
0769 err = counter_sysfs_synapses_add(counter, groups + i, count);
0770 if (err < 0)
0771 return err;
0772
0773
0774 err = counter_count_attrs_create(counter, groups + i, count);
0775 if (err < 0)
0776 return err;
0777 }
0778
0779 return 0;
0780 }
0781
0782 static int counter_num_signals_read(struct counter_device *counter, u8 *val)
0783 {
0784 *val = counter->num_signals;
0785 return 0;
0786 }
0787
0788 static int counter_num_counts_read(struct counter_device *counter, u8 *val)
0789 {
0790 *val = counter->num_counts;
0791 return 0;
0792 }
0793
0794 static int counter_events_queue_size_read(struct counter_device *counter,
0795 u64 *val)
0796 {
0797 *val = kfifo_size(&counter->events);
0798 return 0;
0799 }
0800
0801 static int counter_events_queue_size_write(struct counter_device *counter,
0802 u64 val)
0803 {
0804 DECLARE_KFIFO_PTR(events, struct counter_event);
0805 int err;
0806 unsigned long flags;
0807
0808
0809 err = kfifo_alloc(&events, val, GFP_KERNEL);
0810 if (err)
0811 return err;
0812
0813
0814 mutex_lock(&counter->events_out_lock);
0815 spin_lock_irqsave(&counter->events_in_lock, flags);
0816 kfifo_free(&counter->events);
0817 counter->events.kfifo = events.kfifo;
0818 spin_unlock_irqrestore(&counter->events_in_lock, flags);
0819 mutex_unlock(&counter->events_out_lock);
0820
0821 return 0;
0822 }
0823
0824 static struct counter_comp counter_num_signals_comp =
0825 COUNTER_COMP_DEVICE_U8("num_signals", counter_num_signals_read, NULL);
0826
0827 static struct counter_comp counter_num_counts_comp =
0828 COUNTER_COMP_DEVICE_U8("num_counts", counter_num_counts_read, NULL);
0829
0830 static struct counter_comp counter_events_queue_size_comp =
0831 COUNTER_COMP_DEVICE_U64("events_queue_size",
0832 counter_events_queue_size_read,
0833 counter_events_queue_size_write);
0834
0835 static int counter_sysfs_attr_add(struct counter_device *const counter,
0836 struct counter_attribute_group *cattr_group)
0837 {
0838 const enum counter_scope scope = COUNTER_SCOPE_DEVICE;
0839 struct device *const dev = &counter->dev;
0840 int err;
0841 size_t i;
0842 struct counter_comp *ext;
0843
0844
0845 err = counter_sysfs_signals_add(counter, cattr_group);
0846 if (err < 0)
0847 return err;
0848 cattr_group += counter->num_signals;
0849
0850
0851 err = counter_sysfs_counts_add(counter, cattr_group);
0852 if (err < 0)
0853 return err;
0854 cattr_group += counter->num_counts;
0855
0856
0857 err = counter_name_attr_create(dev, cattr_group, counter->name);
0858 if (err < 0)
0859 return err;
0860
0861
0862 err = counter_attr_create(dev, cattr_group, &counter_num_signals_comp,
0863 scope, NULL);
0864 if (err < 0)
0865 return err;
0866
0867
0868 err = counter_attr_create(dev, cattr_group, &counter_num_counts_comp,
0869 scope, NULL);
0870 if (err < 0)
0871 return err;
0872
0873
0874 err = counter_attr_create(dev, cattr_group,
0875 &counter_events_queue_size_comp, scope, NULL);
0876 if (err < 0)
0877 return err;
0878
0879
0880 for (i = 0; i < counter->num_ext; i++) {
0881 ext = &counter->ext[i];
0882
0883 err = counter_attr_create(dev, cattr_group, ext, scope, NULL);
0884 if (err < 0)
0885 return err;
0886
0887 err = counter_comp_id_attr_create(dev, cattr_group, ext->name,
0888 i);
0889 if (err < 0)
0890 return err;
0891 }
0892
0893 return 0;
0894 }
0895
0896
0897
0898
0899
0900
0901
0902
0903
0904
0905
0906 int counter_sysfs_add(struct counter_device *const counter)
0907 {
0908 struct device *const dev = &counter->dev;
0909 const size_t num_groups = counter->num_signals + counter->num_counts + 1;
0910 struct counter_attribute_group *cattr_groups;
0911 size_t i, j;
0912 int err;
0913 struct attribute_group *groups;
0914 struct counter_attribute *p;
0915
0916
0917 cattr_groups = devm_kcalloc(dev, num_groups, sizeof(*cattr_groups),
0918 GFP_KERNEL);
0919 if (!cattr_groups)
0920 return -ENOMEM;
0921
0922
0923 for (i = 0; i < num_groups; i++)
0924 INIT_LIST_HEAD(&cattr_groups[i].attr_list);
0925
0926
0927 err = counter_sysfs_attr_add(counter, cattr_groups);
0928 if (err < 0)
0929 return err;
0930
0931
0932 dev->groups = devm_kcalloc(dev, num_groups + 1, sizeof(*dev->groups),
0933 GFP_KERNEL);
0934 if (!dev->groups)
0935 return -ENOMEM;
0936
0937
0938 groups = devm_kcalloc(dev, num_groups, sizeof(*groups), GFP_KERNEL);
0939 if (!groups)
0940 return -ENOMEM;
0941
0942
0943 for (i = 0; i < num_groups; i++) {
0944 groups[i].name = cattr_groups[i].name;
0945
0946
0947 groups[i].attrs = devm_kcalloc(dev,
0948 cattr_groups[i].num_attr + 1,
0949 sizeof(*groups[i].attrs),
0950 GFP_KERNEL);
0951 if (!groups[i].attrs)
0952 return -ENOMEM;
0953
0954
0955 j = 0;
0956 list_for_each_entry(p, &cattr_groups[i].attr_list, l)
0957 groups[i].attrs[j++] = &p->dev_attr.attr;
0958
0959
0960 dev->groups[i] = &groups[i];
0961 }
0962
0963 return 0;
0964 }