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