18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2008 by Karsten Keil <kkeil@novell.com> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/slab.h> 78c2ecf20Sopenharmony_ci#include <linux/types.h> 88c2ecf20Sopenharmony_ci#include <linux/stddef.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 118c2ecf20Sopenharmony_ci#include <linux/mISDNif.h> 128c2ecf20Sopenharmony_ci#include "core.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic u_int debug; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Karsten Keil"); 178c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 188c2ecf20Sopenharmony_cimodule_param(debug, uint, S_IRUGO | S_IWUSR); 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic u64 device_ids; 218c2ecf20Sopenharmony_ci#define MAX_DEVICE_ID 63 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic LIST_HEAD(Bprotocols); 248c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(bp_lock); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic void mISDN_dev_release(struct device *dev) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci /* nothing to do: the device is part of its parent's data structure */ 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic ssize_t id_show(struct device *dev, 328c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct mISDNdevice *mdev = dev_to_mISDN(dev); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci if (!mdev) 378c2ecf20Sopenharmony_ci return -ENODEV; 388c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", mdev->id); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(id); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic ssize_t nrbchan_show(struct device *dev, 438c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct mISDNdevice *mdev = dev_to_mISDN(dev); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (!mdev) 488c2ecf20Sopenharmony_ci return -ENODEV; 498c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", mdev->nrbchan); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(nrbchan); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic ssize_t d_protocols_show(struct device *dev, 548c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct mISDNdevice *mdev = dev_to_mISDN(dev); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (!mdev) 598c2ecf20Sopenharmony_ci return -ENODEV; 608c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", mdev->Dprotocols); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(d_protocols); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic ssize_t b_protocols_show(struct device *dev, 658c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct mISDNdevice *mdev = dev_to_mISDN(dev); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (!mdev) 708c2ecf20Sopenharmony_ci return -ENODEV; 718c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", mdev->Bprotocols | get_all_Bprotocols()); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(b_protocols); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic ssize_t protocol_show(struct device *dev, 768c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct mISDNdevice *mdev = dev_to_mISDN(dev); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (!mdev) 818c2ecf20Sopenharmony_ci return -ENODEV; 828c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", mdev->D.protocol); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(protocol); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic ssize_t name_show(struct device *dev, 878c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci strcpy(buf, dev_name(dev)); 908c2ecf20Sopenharmony_ci return strlen(buf); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(name); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#if 0 /* hangs */ 958c2ecf20Sopenharmony_cistatic ssize_t name_set(struct device *dev, struct device_attribute *attr, 968c2ecf20Sopenharmony_ci const char *buf, size_t count) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci int err = 0; 998c2ecf20Sopenharmony_ci char *out = kmalloc(count + 1, GFP_KERNEL); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (!out) 1028c2ecf20Sopenharmony_ci return -ENOMEM; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci memcpy(out, buf, count); 1058c2ecf20Sopenharmony_ci if (count && out[count - 1] == '\n') 1068c2ecf20Sopenharmony_ci out[--count] = 0; 1078c2ecf20Sopenharmony_ci if (count) 1088c2ecf20Sopenharmony_ci err = device_rename(dev, out); 1098c2ecf20Sopenharmony_ci kfree(out); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return (err < 0) ? err : count; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(name); 1148c2ecf20Sopenharmony_ci#endif 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic ssize_t channelmap_show(struct device *dev, 1178c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct mISDNdevice *mdev = dev_to_mISDN(dev); 1208c2ecf20Sopenharmony_ci char *bp = buf; 1218c2ecf20Sopenharmony_ci int i; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci for (i = 0; i <= mdev->nrbchan; i++) 1248c2ecf20Sopenharmony_ci *bp++ = test_channelmap(i, mdev->channelmap) ? '1' : '0'; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return bp - buf; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(channelmap); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic struct attribute *mISDN_attrs[] = { 1318c2ecf20Sopenharmony_ci &dev_attr_id.attr, 1328c2ecf20Sopenharmony_ci &dev_attr_d_protocols.attr, 1338c2ecf20Sopenharmony_ci &dev_attr_b_protocols.attr, 1348c2ecf20Sopenharmony_ci &dev_attr_protocol.attr, 1358c2ecf20Sopenharmony_ci &dev_attr_channelmap.attr, 1368c2ecf20Sopenharmony_ci &dev_attr_nrbchan.attr, 1378c2ecf20Sopenharmony_ci &dev_attr_name.attr, 1388c2ecf20Sopenharmony_ci NULL, 1398c2ecf20Sopenharmony_ci}; 1408c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(mISDN); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int mISDN_uevent(struct device *dev, struct kobj_uevent_env *env) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci struct mISDNdevice *mdev = dev_to_mISDN(dev); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (!mdev) 1478c2ecf20Sopenharmony_ci return 0; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (add_uevent_var(env, "nchans=%d", mdev->nrbchan)) 1508c2ecf20Sopenharmony_ci return -ENOMEM; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic void mISDN_class_release(struct class *cls) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci /* do nothing, it's static */ 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic struct class mISDN_class = { 1618c2ecf20Sopenharmony_ci .name = "mISDN", 1628c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1638c2ecf20Sopenharmony_ci .dev_uevent = mISDN_uevent, 1648c2ecf20Sopenharmony_ci .dev_groups = mISDN_groups, 1658c2ecf20Sopenharmony_ci .dev_release = mISDN_dev_release, 1668c2ecf20Sopenharmony_ci .class_release = mISDN_class_release, 1678c2ecf20Sopenharmony_ci}; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic int 1708c2ecf20Sopenharmony_ci_get_mdevice(struct device *dev, const void *id) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct mISDNdevice *mdev = dev_to_mISDN(dev); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (!mdev) 1758c2ecf20Sopenharmony_ci return 0; 1768c2ecf20Sopenharmony_ci if (mdev->id != *(const u_int *)id) 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci return 1; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistruct mISDNdevice 1828c2ecf20Sopenharmony_ci*get_mdevice(u_int id) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci return dev_to_mISDN(class_find_device(&mISDN_class, NULL, &id, 1858c2ecf20Sopenharmony_ci _get_mdevice)); 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int 1898c2ecf20Sopenharmony_ci_get_mdevice_count(struct device *dev, void *cnt) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci *(int *)cnt += 1; 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ciint 1968c2ecf20Sopenharmony_ciget_mdevice_count(void) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci int cnt = 0; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci class_for_each_device(&mISDN_class, NULL, &cnt, _get_mdevice_count); 2018c2ecf20Sopenharmony_ci return cnt; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic int 2058c2ecf20Sopenharmony_ciget_free_devid(void) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci u_int i; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci for (i = 0; i <= MAX_DEVICE_ID; i++) 2108c2ecf20Sopenharmony_ci if (!test_and_set_bit(i, (u_long *)&device_ids)) 2118c2ecf20Sopenharmony_ci break; 2128c2ecf20Sopenharmony_ci if (i > MAX_DEVICE_ID) 2138c2ecf20Sopenharmony_ci return -EBUSY; 2148c2ecf20Sopenharmony_ci return i; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ciint 2188c2ecf20Sopenharmony_cimISDN_register_device(struct mISDNdevice *dev, 2198c2ecf20Sopenharmony_ci struct device *parent, char *name) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci int err; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci err = get_free_devid(); 2248c2ecf20Sopenharmony_ci if (err < 0) 2258c2ecf20Sopenharmony_ci return err; 2268c2ecf20Sopenharmony_ci dev->id = err; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci device_initialize(&dev->dev); 2298c2ecf20Sopenharmony_ci if (name && name[0]) 2308c2ecf20Sopenharmony_ci dev_set_name(&dev->dev, "%s", name); 2318c2ecf20Sopenharmony_ci else 2328c2ecf20Sopenharmony_ci dev_set_name(&dev->dev, "mISDN%d", dev->id); 2338c2ecf20Sopenharmony_ci if (debug & DEBUG_CORE) 2348c2ecf20Sopenharmony_ci printk(KERN_DEBUG "mISDN_register %s %d\n", 2358c2ecf20Sopenharmony_ci dev_name(&dev->dev), dev->id); 2368c2ecf20Sopenharmony_ci dev->dev.class = &mISDN_class; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci err = create_stack(dev); 2398c2ecf20Sopenharmony_ci if (err) 2408c2ecf20Sopenharmony_ci goto error1; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci dev->dev.platform_data = dev; 2438c2ecf20Sopenharmony_ci dev->dev.parent = parent; 2448c2ecf20Sopenharmony_ci dev_set_drvdata(&dev->dev, dev); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci err = device_add(&dev->dev); 2478c2ecf20Sopenharmony_ci if (err) 2488c2ecf20Sopenharmony_ci goto error3; 2498c2ecf20Sopenharmony_ci return 0; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cierror3: 2528c2ecf20Sopenharmony_ci delete_stack(dev); 2538c2ecf20Sopenharmony_cierror1: 2548c2ecf20Sopenharmony_ci put_device(&dev->dev); 2558c2ecf20Sopenharmony_ci return err; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDN_register_device); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_civoid 2618c2ecf20Sopenharmony_cimISDN_unregister_device(struct mISDNdevice *dev) { 2628c2ecf20Sopenharmony_ci if (debug & DEBUG_CORE) 2638c2ecf20Sopenharmony_ci printk(KERN_DEBUG "mISDN_unregister %s %d\n", 2648c2ecf20Sopenharmony_ci dev_name(&dev->dev), dev->id); 2658c2ecf20Sopenharmony_ci /* sysfs_remove_link(&dev->dev.kobj, "device"); */ 2668c2ecf20Sopenharmony_ci device_del(&dev->dev); 2678c2ecf20Sopenharmony_ci dev_set_drvdata(&dev->dev, NULL); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci test_and_clear_bit(dev->id, (u_long *)&device_ids); 2708c2ecf20Sopenharmony_ci delete_stack(dev); 2718c2ecf20Sopenharmony_ci put_device(&dev->dev); 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDN_unregister_device); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ciu_int 2768c2ecf20Sopenharmony_ciget_all_Bprotocols(void) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct Bprotocol *bp; 2798c2ecf20Sopenharmony_ci u_int m = 0; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci read_lock(&bp_lock); 2828c2ecf20Sopenharmony_ci list_for_each_entry(bp, &Bprotocols, list) 2838c2ecf20Sopenharmony_ci m |= bp->Bprotocols; 2848c2ecf20Sopenharmony_ci read_unlock(&bp_lock); 2858c2ecf20Sopenharmony_ci return m; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistruct Bprotocol * 2898c2ecf20Sopenharmony_ciget_Bprotocol4mask(u_int m) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct Bprotocol *bp; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci read_lock(&bp_lock); 2948c2ecf20Sopenharmony_ci list_for_each_entry(bp, &Bprotocols, list) 2958c2ecf20Sopenharmony_ci if (bp->Bprotocols & m) { 2968c2ecf20Sopenharmony_ci read_unlock(&bp_lock); 2978c2ecf20Sopenharmony_ci return bp; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci read_unlock(&bp_lock); 3008c2ecf20Sopenharmony_ci return NULL; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistruct Bprotocol * 3048c2ecf20Sopenharmony_ciget_Bprotocol4id(u_int id) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci u_int m; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (id < ISDN_P_B_START || id > 63) { 3098c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s id not in range %d\n", 3108c2ecf20Sopenharmony_ci __func__, id); 3118c2ecf20Sopenharmony_ci return NULL; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci m = 1 << (id & ISDN_P_B_MASK); 3148c2ecf20Sopenharmony_ci return get_Bprotocol4mask(m); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ciint 3188c2ecf20Sopenharmony_cimISDN_register_Bprotocol(struct Bprotocol *bp) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci u_long flags; 3218c2ecf20Sopenharmony_ci struct Bprotocol *old; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (debug & DEBUG_CORE) 3248c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s/%x\n", __func__, 3258c2ecf20Sopenharmony_ci bp->name, bp->Bprotocols); 3268c2ecf20Sopenharmony_ci old = get_Bprotocol4mask(bp->Bprotocols); 3278c2ecf20Sopenharmony_ci if (old) { 3288c2ecf20Sopenharmony_ci printk(KERN_WARNING 3298c2ecf20Sopenharmony_ci "register duplicate protocol old %s/%x new %s/%x\n", 3308c2ecf20Sopenharmony_ci old->name, old->Bprotocols, bp->name, bp->Bprotocols); 3318c2ecf20Sopenharmony_ci return -EBUSY; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci write_lock_irqsave(&bp_lock, flags); 3348c2ecf20Sopenharmony_ci list_add_tail(&bp->list, &Bprotocols); 3358c2ecf20Sopenharmony_ci write_unlock_irqrestore(&bp_lock, flags); 3368c2ecf20Sopenharmony_ci return 0; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDN_register_Bprotocol); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_civoid 3418c2ecf20Sopenharmony_cimISDN_unregister_Bprotocol(struct Bprotocol *bp) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci u_long flags; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (debug & DEBUG_CORE) 3468c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s/%x\n", __func__, bp->name, 3478c2ecf20Sopenharmony_ci bp->Bprotocols); 3488c2ecf20Sopenharmony_ci write_lock_irqsave(&bp_lock, flags); 3498c2ecf20Sopenharmony_ci list_del(&bp->list); 3508c2ecf20Sopenharmony_ci write_unlock_irqrestore(&bp_lock, flags); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDN_unregister_Bprotocol); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic const char *msg_no_channel = "<no channel>"; 3558c2ecf20Sopenharmony_cistatic const char *msg_no_stack = "<no stack>"; 3568c2ecf20Sopenharmony_cistatic const char *msg_no_stackdev = "<no stack device>"; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ciconst char *mISDNDevName4ch(struct mISDNchannel *ch) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci if (!ch) 3618c2ecf20Sopenharmony_ci return msg_no_channel; 3628c2ecf20Sopenharmony_ci if (!ch->st) 3638c2ecf20Sopenharmony_ci return msg_no_stack; 3648c2ecf20Sopenharmony_ci if (!ch->st->dev) 3658c2ecf20Sopenharmony_ci return msg_no_stackdev; 3668c2ecf20Sopenharmony_ci return dev_name(&ch->st->dev->dev); 3678c2ecf20Sopenharmony_ci}; 3688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDNDevName4ch); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int 3718c2ecf20Sopenharmony_cimISDNInit(void) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci int err; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci printk(KERN_INFO "Modular ISDN core version %d.%d.%d\n", 3768c2ecf20Sopenharmony_ci MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE); 3778c2ecf20Sopenharmony_ci mISDN_init_clock(&debug); 3788c2ecf20Sopenharmony_ci mISDN_initstack(&debug); 3798c2ecf20Sopenharmony_ci err = class_register(&mISDN_class); 3808c2ecf20Sopenharmony_ci if (err) 3818c2ecf20Sopenharmony_ci goto error1; 3828c2ecf20Sopenharmony_ci err = mISDN_inittimer(&debug); 3838c2ecf20Sopenharmony_ci if (err) 3848c2ecf20Sopenharmony_ci goto error2; 3858c2ecf20Sopenharmony_ci err = Isdnl1_Init(&debug); 3868c2ecf20Sopenharmony_ci if (err) 3878c2ecf20Sopenharmony_ci goto error3; 3888c2ecf20Sopenharmony_ci err = Isdnl2_Init(&debug); 3898c2ecf20Sopenharmony_ci if (err) 3908c2ecf20Sopenharmony_ci goto error4; 3918c2ecf20Sopenharmony_ci err = misdn_sock_init(&debug); 3928c2ecf20Sopenharmony_ci if (err) 3938c2ecf20Sopenharmony_ci goto error5; 3948c2ecf20Sopenharmony_ci return 0; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cierror5: 3978c2ecf20Sopenharmony_ci Isdnl2_cleanup(); 3988c2ecf20Sopenharmony_cierror4: 3998c2ecf20Sopenharmony_ci Isdnl1_cleanup(); 4008c2ecf20Sopenharmony_cierror3: 4018c2ecf20Sopenharmony_ci mISDN_timer_cleanup(); 4028c2ecf20Sopenharmony_cierror2: 4038c2ecf20Sopenharmony_ci class_unregister(&mISDN_class); 4048c2ecf20Sopenharmony_cierror1: 4058c2ecf20Sopenharmony_ci return err; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic void mISDN_cleanup(void) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci misdn_sock_cleanup(); 4118c2ecf20Sopenharmony_ci Isdnl2_cleanup(); 4128c2ecf20Sopenharmony_ci Isdnl1_cleanup(); 4138c2ecf20Sopenharmony_ci mISDN_timer_cleanup(); 4148c2ecf20Sopenharmony_ci class_unregister(&mISDN_class); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci printk(KERN_DEBUG "mISDNcore unloaded\n"); 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cimodule_init(mISDNInit); 4208c2ecf20Sopenharmony_cimodule_exit(mISDN_cleanup); 421