linux/drivers/isdn/mISDN/core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright 2008  by Karsten Keil <kkeil@novell.com>
   4 */
   5
   6#include <linux/slab.h>
   7#include <linux/types.h>
   8#include <linux/stddef.h>
   9#include <linux/module.h>
  10#include <linux/spinlock.h>
  11#include <linux/mISDNif.h>
  12#include "core.h"
  13
  14static u_int debug;
  15
  16MODULE_AUTHOR("Karsten Keil");
  17MODULE_LICENSE("GPL");
  18module_param(debug, uint, S_IRUGO | S_IWUSR);
  19
  20static u64              device_ids;
  21#define MAX_DEVICE_ID   63
  22
  23static LIST_HEAD(Bprotocols);
  24static DEFINE_RWLOCK(bp_lock);
  25
  26static void mISDN_dev_release(struct device *dev)
  27{
  28        /* nothing to do: the device is part of its parent's data structure */
  29}
  30
  31static ssize_t id_show(struct device *dev,
  32                       struct device_attribute *attr, char *buf)
  33{
  34        struct mISDNdevice *mdev = dev_to_mISDN(dev);
  35
  36        if (!mdev)
  37                return -ENODEV;
  38        return sprintf(buf, "%d\n", mdev->id);
  39}
  40static DEVICE_ATTR_RO(id);
  41
  42static ssize_t nrbchan_show(struct device *dev,
  43                            struct device_attribute *attr, char *buf)
  44{
  45        struct mISDNdevice *mdev = dev_to_mISDN(dev);
  46
  47        if (!mdev)
  48                return -ENODEV;
  49        return sprintf(buf, "%d\n", mdev->nrbchan);
  50}
  51static DEVICE_ATTR_RO(nrbchan);
  52
  53static ssize_t d_protocols_show(struct device *dev,
  54                                struct device_attribute *attr, char *buf)
  55{
  56        struct mISDNdevice *mdev = dev_to_mISDN(dev);
  57
  58        if (!mdev)
  59                return -ENODEV;
  60        return sprintf(buf, "%d\n", mdev->Dprotocols);
  61}
  62static DEVICE_ATTR_RO(d_protocols);
  63
  64static ssize_t b_protocols_show(struct device *dev,
  65                                struct device_attribute *attr, char *buf)
  66{
  67        struct mISDNdevice *mdev = dev_to_mISDN(dev);
  68
  69        if (!mdev)
  70                return -ENODEV;
  71        return sprintf(buf, "%d\n", mdev->Bprotocols | get_all_Bprotocols());
  72}
  73static DEVICE_ATTR_RO(b_protocols);
  74
  75static ssize_t protocol_show(struct device *dev,
  76                             struct device_attribute *attr, char *buf)
  77{
  78        struct mISDNdevice *mdev = dev_to_mISDN(dev);
  79
  80        if (!mdev)
  81                return -ENODEV;
  82        return sprintf(buf, "%d\n", mdev->D.protocol);
  83}
  84static DEVICE_ATTR_RO(protocol);
  85
  86static ssize_t name_show(struct device *dev,
  87                         struct device_attribute *attr, char *buf)
  88{
  89        strcpy(buf, dev_name(dev));
  90        return strlen(buf);
  91}
  92static DEVICE_ATTR_RO(name);
  93
  94#if 0 /* hangs */
  95static ssize_t name_set(struct device *dev, struct device_attribute *attr,
  96                        const char *buf, size_t count)
  97{
  98        int err = 0;
  99        char *out = kmalloc(count + 1, GFP_KERNEL);
 100
 101        if (!out)
 102                return -ENOMEM;
 103
 104        memcpy(out, buf, count);
 105        if (count && out[count - 1] == '\n')
 106                out[--count] = 0;
 107        if (count)
 108                err = device_rename(dev, out);
 109        kfree(out);
 110
 111        return (err < 0) ? err : count;
 112}
 113static DEVICE_ATTR_RW(name);
 114#endif
 115
 116static ssize_t channelmap_show(struct device *dev,
 117                               struct device_attribute *attr, char *buf)
 118{
 119        struct mISDNdevice *mdev = dev_to_mISDN(dev);
 120        char *bp = buf;
 121        int i;
 122
 123        for (i = 0; i <= mdev->nrbchan; i++)
 124                *bp++ = test_channelmap(i, mdev->channelmap) ? '1' : '0';
 125
 126        return bp - buf;
 127}
 128static DEVICE_ATTR_RO(channelmap);
 129
 130static struct attribute *mISDN_attrs[] = {
 131        &dev_attr_id.attr,
 132        &dev_attr_d_protocols.attr,
 133        &dev_attr_b_protocols.attr,
 134        &dev_attr_protocol.attr,
 135        &dev_attr_channelmap.attr,
 136        &dev_attr_nrbchan.attr,
 137        &dev_attr_name.attr,
 138        NULL,
 139};
 140ATTRIBUTE_GROUPS(mISDN);
 141
 142static int mISDN_uevent(struct device *dev, struct kobj_uevent_env *env)
 143{
 144        struct mISDNdevice *mdev = dev_to_mISDN(dev);
 145
 146        if (!mdev)
 147                return 0;
 148
 149        if (add_uevent_var(env, "nchans=%d", mdev->nrbchan))
 150                return -ENOMEM;
 151
 152        return 0;
 153}
 154
 155static void mISDN_class_release(struct class *cls)
 156{
 157        /* do nothing, it's static */
 158}
 159
 160static struct class mISDN_class = {
 161        .name = "mISDN",
 162        .owner = THIS_MODULE,
 163        .dev_uevent = mISDN_uevent,
 164        .dev_groups = mISDN_groups,
 165        .dev_release = mISDN_dev_release,
 166        .class_release = mISDN_class_release,
 167};
 168
 169static int
 170_get_mdevice(struct device *dev, const void *id)
 171{
 172        struct mISDNdevice *mdev = dev_to_mISDN(dev);
 173
 174        if (!mdev)
 175                return 0;
 176        if (mdev->id != *(const u_int *)id)
 177                return 0;
 178        return 1;
 179}
 180
 181struct mISDNdevice
 182*get_mdevice(u_int id)
 183{
 184        return dev_to_mISDN(class_find_device(&mISDN_class, NULL, &id,
 185                                              _get_mdevice));
 186}
 187
 188static int
 189_get_mdevice_count(struct device *dev, void *cnt)
 190{
 191        *(int *)cnt += 1;
 192        return 0;
 193}
 194
 195int
 196get_mdevice_count(void)
 197{
 198        int cnt = 0;
 199
 200        class_for_each_device(&mISDN_class, NULL, &cnt, _get_mdevice_count);
 201        return cnt;
 202}
 203
 204static int
 205get_free_devid(void)
 206{
 207        u_int   i;
 208
 209        for (i = 0; i <= MAX_DEVICE_ID; i++)
 210                if (!test_and_set_bit(i, (u_long *)&device_ids))
 211                        break;
 212        if (i > MAX_DEVICE_ID)
 213                return -EBUSY;
 214        return i;
 215}
 216
 217int
 218mISDN_register_device(struct mISDNdevice *dev,
 219                      struct device *parent, char *name)
 220{
 221        int     err;
 222
 223        err = get_free_devid();
 224        if (err < 0)
 225                goto error1;
 226        dev->id = err;
 227
 228        device_initialize(&dev->dev);
 229        if (name && name[0])
 230                dev_set_name(&dev->dev, "%s", name);
 231        else
 232                dev_set_name(&dev->dev, "mISDN%d", dev->id);
 233        if (debug & DEBUG_CORE)
 234                printk(KERN_DEBUG "mISDN_register %s %d\n",
 235                       dev_name(&dev->dev), dev->id);
 236        err = create_stack(dev);
 237        if (err)
 238                goto error1;
 239
 240        dev->dev.class = &mISDN_class;
 241        dev->dev.platform_data = dev;
 242        dev->dev.parent = parent;
 243        dev_set_drvdata(&dev->dev, dev);
 244
 245        err = device_add(&dev->dev);
 246        if (err)
 247                goto error3;
 248        return 0;
 249
 250error3:
 251        delete_stack(dev);
 252        return err;
 253error1:
 254        return err;
 255
 256}
 257EXPORT_SYMBOL(mISDN_register_device);
 258
 259void
 260mISDN_unregister_device(struct mISDNdevice *dev) {
 261        if (debug & DEBUG_CORE)
 262                printk(KERN_DEBUG "mISDN_unregister %s %d\n",
 263                       dev_name(&dev->dev), dev->id);
 264        /* sysfs_remove_link(&dev->dev.kobj, "device"); */
 265        device_del(&dev->dev);
 266        dev_set_drvdata(&dev->dev, NULL);
 267
 268        test_and_clear_bit(dev->id, (u_long *)&device_ids);
 269        delete_stack(dev);
 270        put_device(&dev->dev);
 271}
 272EXPORT_SYMBOL(mISDN_unregister_device);
 273
 274u_int
 275get_all_Bprotocols(void)
 276{
 277        struct Bprotocol        *bp;
 278        u_int   m = 0;
 279
 280        read_lock(&bp_lock);
 281        list_for_each_entry(bp, &Bprotocols, list)
 282                m |= bp->Bprotocols;
 283        read_unlock(&bp_lock);
 284        return m;
 285}
 286
 287struct Bprotocol *
 288get_Bprotocol4mask(u_int m)
 289{
 290        struct Bprotocol        *bp;
 291
 292        read_lock(&bp_lock);
 293        list_for_each_entry(bp, &Bprotocols, list)
 294                if (bp->Bprotocols & m) {
 295                        read_unlock(&bp_lock);
 296                        return bp;
 297                }
 298        read_unlock(&bp_lock);
 299        return NULL;
 300}
 301
 302struct Bprotocol *
 303get_Bprotocol4id(u_int id)
 304{
 305        u_int   m;
 306
 307        if (id < ISDN_P_B_START || id > 63) {
 308                printk(KERN_WARNING "%s id not in range  %d\n",
 309                       __func__, id);
 310                return NULL;
 311        }
 312        m = 1 << (id & ISDN_P_B_MASK);
 313        return get_Bprotocol4mask(m);
 314}
 315
 316int
 317mISDN_register_Bprotocol(struct Bprotocol *bp)
 318{
 319        u_long                  flags;
 320        struct Bprotocol        *old;
 321
 322        if (debug & DEBUG_CORE)
 323                printk(KERN_DEBUG "%s: %s/%x\n", __func__,
 324                       bp->name, bp->Bprotocols);
 325        old = get_Bprotocol4mask(bp->Bprotocols);
 326        if (old) {
 327                printk(KERN_WARNING
 328                       "register duplicate protocol old %s/%x new %s/%x\n",
 329                       old->name, old->Bprotocols, bp->name, bp->Bprotocols);
 330                return -EBUSY;
 331        }
 332        write_lock_irqsave(&bp_lock, flags);
 333        list_add_tail(&bp->list, &Bprotocols);
 334        write_unlock_irqrestore(&bp_lock, flags);
 335        return 0;
 336}
 337EXPORT_SYMBOL(mISDN_register_Bprotocol);
 338
 339void
 340mISDN_unregister_Bprotocol(struct Bprotocol *bp)
 341{
 342        u_long  flags;
 343
 344        if (debug & DEBUG_CORE)
 345                printk(KERN_DEBUG "%s: %s/%x\n", __func__, bp->name,
 346                       bp->Bprotocols);
 347        write_lock_irqsave(&bp_lock, flags);
 348        list_del(&bp->list);
 349        write_unlock_irqrestore(&bp_lock, flags);
 350}
 351EXPORT_SYMBOL(mISDN_unregister_Bprotocol);
 352
 353static const char *msg_no_channel = "<no channel>";
 354static const char *msg_no_stack = "<no stack>";
 355static const char *msg_no_stackdev = "<no stack device>";
 356
 357const char *mISDNDevName4ch(struct mISDNchannel *ch)
 358{
 359        if (!ch)
 360                return msg_no_channel;
 361        if (!ch->st)
 362                return msg_no_stack;
 363        if (!ch->st->dev)
 364                return msg_no_stackdev;
 365        return dev_name(&ch->st->dev->dev);
 366};
 367EXPORT_SYMBOL(mISDNDevName4ch);
 368
 369static int
 370mISDNInit(void)
 371{
 372        int     err;
 373
 374        printk(KERN_INFO "Modular ISDN core version %d.%d.%d\n",
 375               MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE);
 376        mISDN_init_clock(&debug);
 377        mISDN_initstack(&debug);
 378        err = class_register(&mISDN_class);
 379        if (err)
 380                goto error1;
 381        err = mISDN_inittimer(&debug);
 382        if (err)
 383                goto error2;
 384        err = Isdnl1_Init(&debug);
 385        if (err)
 386                goto error3;
 387        err = Isdnl2_Init(&debug);
 388        if (err)
 389                goto error4;
 390        err = misdn_sock_init(&debug);
 391        if (err)
 392                goto error5;
 393        return 0;
 394
 395error5:
 396        Isdnl2_cleanup();
 397error4:
 398        Isdnl1_cleanup();
 399error3:
 400        mISDN_timer_cleanup();
 401error2:
 402        class_unregister(&mISDN_class);
 403error1:
 404        return err;
 405}
 406
 407static void mISDN_cleanup(void)
 408{
 409        misdn_sock_cleanup();
 410        Isdnl2_cleanup();
 411        Isdnl1_cleanup();
 412        mISDN_timer_cleanup();
 413        class_unregister(&mISDN_class);
 414
 415        printk(KERN_DEBUG "mISDNcore unloaded\n");
 416}
 417
 418module_init(mISDNInit);
 419module_exit(mISDN_cleanup);
 420