123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- /*
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
- #include <linux/types.h>
- #include <linux/stddef.h>
- #include <linux/module.h>
- #include <linux/spinlock.h>
- #include <linux/mISDNif.h>
- #include "core.h"
- static u_int debug;
- MODULE_AUTHOR("Karsten Keil");
- MODULE_LICENSE("GPL");
- module_param(debug, uint, S_IRUGO | S_IWUSR);
- static LIST_HEAD(devices);
- DEFINE_RWLOCK(device_lock);
- static u64 device_ids;
- #define MAX_DEVICE_ID 63
- static LIST_HEAD(Bprotocols);
- DEFINE_RWLOCK(bp_lock);
- struct mISDNdevice
- *get_mdevice(u_int id)
- {
- struct mISDNdevice *dev;
- read_lock(&device_lock);
- list_for_each_entry(dev, &devices, D.list)
- if (dev->id == id) {
- read_unlock(&device_lock);
- return dev;
- }
- read_unlock(&device_lock);
- return NULL;
- }
- int
- get_mdevice_count(void)
- {
- struct mISDNdevice *dev;
- int cnt = 0;
- read_lock(&device_lock);
- list_for_each_entry(dev, &devices, D.list)
- cnt++;
- read_unlock(&device_lock);
- return cnt;
- }
- static int
- get_free_devid(void)
- {
- u_int i;
- for (i = 0; i <= MAX_DEVICE_ID; i++)
- if (!test_and_set_bit(i, (u_long *)&device_ids))
- return i;
- return -1;
- }
- int
- mISDN_register_device(struct mISDNdevice *dev, char *name)
- {
- u_long flags;
- int err;
- dev->id = get_free_devid();
- if (dev->id < 0)
- return -EBUSY;
- if (name && name[0])
- strcpy(dev->name, name);
- else
- sprintf(dev->name, "mISDN%d", dev->id);
- if (debug & DEBUG_CORE)
- printk(KERN_DEBUG "mISDN_register %s %d\n",
- dev->name, dev->id);
- err = create_stack(dev);
- if (err)
- return err;
- write_lock_irqsave(&device_lock, flags);
- list_add_tail(&dev->D.list, &devices);
- write_unlock_irqrestore(&device_lock, flags);
- return 0;
- }
- EXPORT_SYMBOL(mISDN_register_device);
- void
- mISDN_unregister_device(struct mISDNdevice *dev) {
- u_long flags;
- if (debug & DEBUG_CORE)
- printk(KERN_DEBUG "mISDN_unregister %s %d\n",
- dev->name, dev->id);
- write_lock_irqsave(&device_lock, flags);
- list_del(&dev->D.list);
- write_unlock_irqrestore(&device_lock, flags);
- test_and_clear_bit(dev->id, (u_long *)&device_ids);
- delete_stack(dev);
- }
- EXPORT_SYMBOL(mISDN_unregister_device);
- u_int
- get_all_Bprotocols(void)
- {
- struct Bprotocol *bp;
- u_int m = 0;
- read_lock(&bp_lock);
- list_for_each_entry(bp, &Bprotocols, list)
- m |= bp->Bprotocols;
- read_unlock(&bp_lock);
- return m;
- }
- struct Bprotocol *
- get_Bprotocol4mask(u_int m)
- {
- struct Bprotocol *bp;
- read_lock(&bp_lock);
- list_for_each_entry(bp, &Bprotocols, list)
- if (bp->Bprotocols & m) {
- read_unlock(&bp_lock);
- return bp;
- }
- read_unlock(&bp_lock);
- return NULL;
- }
- struct Bprotocol *
- get_Bprotocol4id(u_int id)
- {
- u_int m;
- if (id < ISDN_P_B_START || id > 63) {
- printk(KERN_WARNING "%s id not in range %d\n",
- __func__, id);
- return NULL;
- }
- m = 1 << (id & ISDN_P_B_MASK);
- return get_Bprotocol4mask(m);
- }
- int
- mISDN_register_Bprotocol(struct Bprotocol *bp)
- {
- u_long flags;
- struct Bprotocol *old;
- if (debug & DEBUG_CORE)
- printk(KERN_DEBUG "%s: %s/%x\n", __func__,
- bp->name, bp->Bprotocols);
- old = get_Bprotocol4mask(bp->Bprotocols);
- if (old) {
- printk(KERN_WARNING
- "register duplicate protocol old %s/%x new %s/%x\n",
- old->name, old->Bprotocols, bp->name, bp->Bprotocols);
- return -EBUSY;
- }
- write_lock_irqsave(&bp_lock, flags);
- list_add_tail(&bp->list, &Bprotocols);
- write_unlock_irqrestore(&bp_lock, flags);
- return 0;
- }
- EXPORT_SYMBOL(mISDN_register_Bprotocol);
- void
- mISDN_unregister_Bprotocol(struct Bprotocol *bp)
- {
- u_long flags;
- if (debug & DEBUG_CORE)
- printk(KERN_DEBUG "%s: %s/%x\n", __func__, bp->name,
- bp->Bprotocols);
- write_lock_irqsave(&bp_lock, flags);
- list_del(&bp->list);
- write_unlock_irqrestore(&bp_lock, flags);
- }
- EXPORT_SYMBOL(mISDN_unregister_Bprotocol);
- int
- mISDNInit(void)
- {
- int err;
- printk(KERN_INFO "Modular ISDN core version %d.%d.%d\n",
- MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE);
- mISDN_initstack(&debug);
- err = mISDN_inittimer(&debug);
- if (err)
- goto error;
- err = l1_init(&debug);
- if (err) {
- mISDN_timer_cleanup();
- goto error;
- }
- err = Isdnl2_Init(&debug);
- if (err) {
- mISDN_timer_cleanup();
- l1_cleanup();
- goto error;
- }
- err = misdn_sock_init(&debug);
- if (err) {
- mISDN_timer_cleanup();
- l1_cleanup();
- Isdnl2_cleanup();
- }
- error:
- return err;
- }
- void mISDN_cleanup(void)
- {
- misdn_sock_cleanup();
- mISDN_timer_cleanup();
- l1_cleanup();
- Isdnl2_cleanup();
- if (!list_empty(&devices))
- printk(KERN_ERR "%s devices still registered\n", __func__);
- if (!list_empty(&Bprotocols))
- printk(KERN_ERR "%s Bprotocols still registered\n", __func__);
- printk(KERN_DEBUG "mISDNcore unloaded\n");
- }
- module_init(mISDNInit);
- module_exit(mISDN_cleanup);
|