📄 kcapi.c
字号:
/* $Id: kcapi.c,v 1.1.2.8 2004/03/26 19:57:20 armin Exp $ * * Kernel CAPI 2.0 Module * * Copyright 1999 by Carsten Paeth <calle@calle.de> * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name> * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * */#define CONFIG_AVMB1_COMPAT#include "kcapi.h"#include <linux/module.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <linux/proc_fs.h>#include <linux/seq_file.h>#include <linux/skbuff.h>#include <linux/workqueue.h>#include <linux/capi.h>#include <linux/kernelcapi.h>#include <linux/init.h>#include <linux/moduleparam.h>#include <linux/delay.h>#include <asm/uaccess.h>#include <linux/isdn/capicmd.h>#include <linux/isdn/capiutil.h>#ifdef CONFIG_AVMB1_COMPAT#include <linux/b1lli.h>#endifstatic char *revision = "$Revision: 1.1.2.8 $";/* ------------------------------------------------------------- */static int showcapimsgs = 0;MODULE_DESCRIPTION("CAPI4Linux: kernel CAPI layer");MODULE_AUTHOR("Carsten Paeth");MODULE_LICENSE("GPL");module_param(showcapimsgs, uint, 0);/* ------------------------------------------------------------- */struct capi_notifier { struct work_struct work; unsigned int cmd; u32 controller; u16 applid; u32 ncci;};/* ------------------------------------------------------------- */static struct capi_version driver_version = {2, 0, 1, 1<<4};static char driver_serial[CAPI_SERIAL_LEN] = "0004711";static char capi_manufakturer[64] = "AVM Berlin";#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)LIST_HEAD(capi_drivers);DEFINE_RWLOCK(capi_drivers_list_lock);static DEFINE_RWLOCK(application_lock);static DECLARE_MUTEX(controller_sem);struct capi20_appl *capi_applications[CAPI_MAXAPPL];struct capi_ctr *capi_cards[CAPI_MAXCONTR];static int ncards;/* -------- controller ref counting -------------------------------------- */static inline struct capi_ctr *capi_ctr_get(struct capi_ctr *card){ if (!try_module_get(card->owner)) return NULL; return card;}static inline voidcapi_ctr_put(struct capi_ctr *card){ module_put(card->owner);}/* ------------------------------------------------------------- */static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr){ if (contr - 1 >= CAPI_MAXCONTR) return NULL; return capi_cards[contr - 1];}static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid){ if (applid - 1 >= CAPI_MAXAPPL) return NULL; return capi_applications[applid - 1];}/* -------- util functions ------------------------------------ */static inline int capi_cmd_valid(u8 cmd){ switch (cmd) { case CAPI_ALERT: case CAPI_CONNECT: case CAPI_CONNECT_ACTIVE: case CAPI_CONNECT_B3_ACTIVE: case CAPI_CONNECT_B3: case CAPI_CONNECT_B3_T90_ACTIVE: case CAPI_DATA_B3: case CAPI_DISCONNECT_B3: case CAPI_DISCONNECT: case CAPI_FACILITY: case CAPI_INFO: case CAPI_LISTEN: case CAPI_MANUFACTURER: case CAPI_RESET_B3: case CAPI_SELECT_B_PROTOCOL: return 1; } return 0;}static inline int capi_subcmd_valid(u8 subcmd){ switch (subcmd) { case CAPI_REQ: case CAPI_CONF: case CAPI_IND: case CAPI_RESP: return 1; } return 0;}/* ------------------------------------------------------------ */static void register_appl(struct capi_ctr *card, u16 applid, capi_register_params *rparam){ card = capi_ctr_get(card); if (card) card->register_appl(card, applid, rparam); else printk(KERN_WARNING "%s: cannot get card resources\n", __FUNCTION__);}static void release_appl(struct capi_ctr *card, u16 applid){ DBG("applid %#x", applid); card->release_appl(card, applid); capi_ctr_put(card);}/* -------- KCI_CONTRUP --------------------------------------- */static void notify_up(u32 contr){ struct capi_ctr *card = get_capi_ctr_by_nr(contr); struct capi20_appl *ap; u16 applid; if (showcapimsgs & 1) { printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr); } if (!card) { printk(KERN_WARNING "%s: invalid contr %d\n", __FUNCTION__, contr); return; } for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { ap = get_capi_appl_by_nr(applid); if (!ap || ap->release_in_progress) continue; register_appl(card, applid, &ap->rparam); if (ap->callback && !ap->release_in_progress) ap->callback(KCI_CONTRUP, contr, &card->profile); }}/* -------- KCI_CONTRDOWN ------------------------------------- */static void notify_down(u32 contr){ struct capi20_appl *ap; u16 applid; if (showcapimsgs & 1) { printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr); } for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { ap = get_capi_appl_by_nr(applid); if (ap && ap->callback && !ap->release_in_progress) ap->callback(KCI_CONTRDOWN, contr, NULL); }}static void notify_handler(void *data){ struct capi_notifier *np = data; switch (np->cmd) { case KCI_CONTRUP: notify_up(np->controller); break; case KCI_CONTRDOWN: notify_down(np->controller); break; } kfree(np);}/* * The notifier will result in adding/deleteing of devices. Devices can * only removed in user process, not in bh. */static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci){ struct capi_notifier *np = kmalloc(sizeof(*np), GFP_ATOMIC); if (!np) return -ENOMEM; INIT_WORK(&np->work, notify_handler, np); np->cmd = cmd; np->controller = controller; np->applid = applid; np->ncci = ncci; schedule_work(&np->work); return 0;} /* -------- Receiver ------------------------------------------ */static void recv_handler(void *_ap){ struct sk_buff *skb; struct capi20_appl *ap = (struct capi20_appl *) _ap; if ((!ap) || (ap->release_in_progress)) return; down(&ap->recv_sem); while ((skb = skb_dequeue(&ap->recv_queue))) { if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND) ap->nrecvdatapkt++; else ap->nrecvctlpkt++; ap->recv_message(ap, skb); } up(&ap->recv_sem);}void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb){ struct capi20_appl *ap; int showctl = 0; u8 cmd, subcmd; unsigned long flags; if (card->cardstate != CARD_RUNNING) { printk(KERN_INFO "kcapi: controller %d not active, got: %s", card->cnr, capi_message2str(skb->data)); goto error; } cmd = CAPIMSG_COMMAND(skb->data); subcmd = CAPIMSG_SUBCOMMAND(skb->data); if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) { card->nrecvdatapkt++; if (card->traceflag > 2) showctl |= 2; } else { card->nrecvctlpkt++; if (card->traceflag) showctl |= 2; } showctl |= (card->traceflag & 1); if (showctl & 2) { if (showctl & 1) { printk(KERN_DEBUG "kcapi: got [0x%lx] id#%d %s len=%u\n", (unsigned long) card->cnr, CAPIMSG_APPID(skb->data), capi_cmd2str(cmd, subcmd), CAPIMSG_LEN(skb->data)); } else { printk(KERN_DEBUG "kcapi: got [0x%lx] %s\n", (unsigned long) card->cnr, capi_message2str(skb->data)); } } read_lock_irqsave(&application_lock, flags); ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data)); if ((!ap) || (ap->release_in_progress)) { read_unlock_irqrestore(&application_lock, flags); printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n", CAPIMSG_APPID(skb->data), capi_message2str(skb->data)); goto error; } skb_queue_tail(&ap->recv_queue, skb); schedule_work(&ap->recv_work); read_unlock_irqrestore(&application_lock, flags); return;error: kfree_skb(skb);}EXPORT_SYMBOL(capi_ctr_handle_message);void capi_ctr_ready(struct capi_ctr * card){ card->cardstate = CARD_RUNNING; printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n", card->cnr, card->name); notify_push(KCI_CONTRUP, card->cnr, 0, 0);}EXPORT_SYMBOL(capi_ctr_ready);void capi_ctr_reseted(struct capi_ctr * card){ u16 appl; DBG(""); if (card->cardstate == CARD_DETECTED) return; card->cardstate = CARD_DETECTED; memset(card->manu, 0, sizeof(card->manu)); memset(&card->version, 0, sizeof(card->version)); memset(&card->profile, 0, sizeof(card->profile)); memset(card->serial, 0, sizeof(card->serial)); for (appl = 1; appl <= CAPI_MAXAPPL; appl++) { struct capi20_appl *ap = get_capi_appl_by_nr(appl); if (!ap || ap->release_in_progress) continue; capi_ctr_put(card); } printk(KERN_NOTICE "kcapi: card %d down.\n", card->cnr); notify_push(KCI_CONTRDOWN, card->cnr, 0, 0);}EXPORT_SYMBOL(capi_ctr_reseted);void capi_ctr_suspend_output(struct capi_ctr *card){ if (!card->blocked) { printk(KERN_DEBUG "kcapi: card %d suspend\n", card->cnr); card->blocked = 1; }}EXPORT_SYMBOL(capi_ctr_suspend_output);void capi_ctr_resume_output(struct capi_ctr *card){ if (card->blocked) { printk(KERN_DEBUG "kcapi: card %d resume\n", card->cnr); card->blocked = 0; }}EXPORT_SYMBOL(capi_ctr_resume_output);/* ------------------------------------------------------------- */intattach_capi_ctr(struct capi_ctr *card){ int i; down(&controller_sem); for (i = 0; i < CAPI_MAXCONTR; i++) { if (capi_cards[i] == NULL) break; } if (i == CAPI_MAXCONTR) { up(&controller_sem); printk(KERN_ERR "kcapi: out of controller slots\n"); return -EBUSY; } capi_cards[i] = card; up(&controller_sem); card->nrecvctlpkt = 0; card->nrecvdatapkt = 0; card->nsentctlpkt = 0; card->nsentdatapkt = 0; card->cnr = i + 1; card->cardstate = CARD_DETECTED; card->blocked = 0; card->traceflag = showcapimsgs; sprintf(card->procfn, "capi/controllers/%d", card->cnr); card->procent = create_proc_entry(card->procfn, 0, NULL); if (card->procent) { card->procent->read_proc = (int (*)(char *,char **,off_t,int,int *,void *)) card->ctr_read_proc; card->procent->data = card; } ncards++; printk(KERN_NOTICE "kcapi: Controller %d: %s attached\n", card->cnr, card->name); return 0;}EXPORT_SYMBOL(attach_capi_ctr);int detach_capi_ctr(struct capi_ctr *card){ if (card->cardstate != CARD_DETECTED) capi_ctr_reseted(card); ncards--; if (card->procent) { remove_proc_entry(card->procfn, NULL); card->procent = NULL; } capi_cards[card->cnr - 1] = NULL; printk(KERN_NOTICE "kcapi: Controller %d: %s unregistered\n", card->cnr, card->name); return 0;}EXPORT_SYMBOL(detach_capi_ctr);void register_capi_driver(struct capi_driver *driver){ unsigned long flags; write_lock_irqsave(&capi_drivers_list_lock, flags); list_add_tail(&driver->list, &capi_drivers); write_unlock_irqrestore(&capi_drivers_list_lock, flags);}EXPORT_SYMBOL(register_capi_driver);void unregister_capi_driver(struct capi_driver *driver){ unsigned long flags; write_lock_irqsave(&capi_drivers_list_lock, flags); list_del(&driver->list); write_unlock_irqrestore(&capi_drivers_list_lock, flags);}EXPORT_SYMBOL(unregister_capi_driver);/* ------------------------------------------------------------- *//* -------- CAPI2.0 Interface ---------------------------------- *//* ------------------------------------------------------------- */u16 capi20_isinstalled(void){ int i; for (i = 0; i < CAPI_MAXCONTR; i++) { if (capi_cards[i] && capi_cards[i]->cardstate == CARD_RUNNING) return CAPI_NOERROR; } return CAPI_REGNOTINSTALLED;}EXPORT_SYMBOL(capi20_isinstalled);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -