📄 kcapi.c
字号:
/* $Id: kcapi.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $ * * Kernel CAPI 2.0 Module * * Copyright 1999 by Carsten Paeth <calle@calle.de> * * 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 <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <asm/segment.h>#include <linux/proc_fs.h>#include <linux/skbuff.h>#include <linux/tqueue.h>#include <linux/capi.h>#include <linux/kernelcapi.h>#include <linux/locks.h>#include <linux/init.h>#include <asm/uaccess.h>#include "capicmd.h"#include "capiutil.h"#include "capilli.h"#ifdef CONFIG_AVMB1_COMPAT#include <linux/b1lli.h>#endifstatic char *revision = "$Revision: 1.1.4.1 $";/* ------------------------------------------------------------- */#define CARD_FREE 0#define CARD_DETECTED 1#define CARD_LOADING 2#define CARD_RUNNING 3/* ------------------------------------------------------------- */static int showcapimsgs = 0;MODULE_DESCRIPTION("CAPI4Linux: kernel CAPI layer");MODULE_AUTHOR("Carsten Paeth");MODULE_LICENSE("GPL");MODULE_PARM(showcapimsgs, "i");/* ------------------------------------------------------------- */struct msgidqueue { struct msgidqueue *next; __u16 msgid;};struct capi_ncci { struct capi_ncci *next; __u16 applid; __u32 ncci; __u32 winsize; int nmsg; struct msgidqueue *msgidqueue; struct msgidqueue *msgidlast; struct msgidqueue *msgidfree; struct msgidqueue msgidpool[CAPI_MAXDATAWINDOW];};struct capi_appl { __u16 applid; capi_register_params rparam; int releasing; void *param; void (*signal) (__u16 applid, void *param); struct sk_buff_head recv_queue; int nncci; struct capi_ncci *nccilist; unsigned long nrecvctlpkt; unsigned long nrecvdatapkt; unsigned long nsentctlpkt; unsigned long nsentdatapkt;};struct capi_notifier { struct capi_notifier *next; 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 APPL(a) (&applications[(a)-1])#define VALID_APPLID(a) ((a) && (a) <= CAPI_MAXAPPL && APPL(a)->applid == a)#define APPL_IS_FREE(a) (APPL(a)->applid == 0)#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0);#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0);#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)#define VALID_CARD(c) ((c) > 0 && (c) <= CAPI_MAXCONTR)#define CARD(c) (&cards[(c)-1])#define CARDNR(cp) (((cp)-cards)+1)static struct capi_appl applications[CAPI_MAXAPPL];static struct capi_ctr cards[CAPI_MAXCONTR];static int ncards = 0;static struct sk_buff_head recv_queue;static struct capi_interface_user *capi_users = 0;static spinlock_t capi_users_lock = SPIN_LOCK_UNLOCKED;static struct capi_driver *drivers;static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED;static struct tq_struct tq_state_notify;static struct tq_struct tq_recv_notify;/* -------- util functions ------------------------------------ */static char *cardstate2str(unsigned short cardstate){ switch (cardstate) { default: case CARD_FREE: return "free"; case CARD_DETECTED: return "detected"; case CARD_LOADING: return "loading"; case CARD_RUNNING: return "running"; }}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;}/* -------- /proc functions ----------------------------------- *//* * /proc/capi/applications: * applid l3cnt dblkcnt dblklen #ncci recvqueuelen */static int proc_applications_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ struct capi_appl *ap; int i; int len = 0; for (i=0; i < CAPI_MAXAPPL; i++) { ap = &applications[i]; if (ap->applid == 0) continue; len += sprintf(page+len, "%u %d %d %d %d %d\n", ap->applid, ap->rparam.level3cnt, ap->rparam.datablkcnt, ap->rparam.datablklen, ap->nncci, skb_queue_len(&ap->recv_queue)); if (len <= off) { off -= len; len = 0; } else { if (len-off > count) goto endloop; } }endloop: *start = page+off; if (len < count) *eof = 1; if (len>count) len = count; if (len<0) len = 0; return len;}/* * /proc/capi/ncci: * applid ncci winsize nblk */static int proc_ncci_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ struct capi_appl *ap; struct capi_ncci *np; int i; int len = 0; for (i=0; i < CAPI_MAXAPPL; i++) { ap = &applications[i]; if (ap->applid == 0) continue; for (np = ap->nccilist; np; np = np->next) { len += sprintf(page+len, "%d 0x%x %d %d\n", np->applid, np->ncci, np->winsize, np->nmsg); if (len <= off) { off -= len; len = 0; } else { if (len-off > count) goto endloop; } } }endloop: *start = page+off; if (len < count) *eof = 1; if (len>count) len = count; if (len<0) len = 0; return len;}/* * /proc/capi/driver: * driver ncontroller */static int proc_driver_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ struct capi_driver *driver; int len = 0; spin_lock(&drivers_lock); for (driver = drivers; driver; driver = driver->next) { len += sprintf(page+len, "%-32s %d %s\n", driver->name, driver->ncontroller, driver->revision); if (len <= off) { off -= len; len = 0; } else { if (len-off > count) goto endloop; } }endloop: spin_unlock(&drivers_lock); *start = page+off; if (len < count) *eof = 1; if (len>count) len = count; if (len<0) len = 0; return len;}/* * /proc/capi/users: * name */static int proc_users_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ struct capi_interface_user *cp; int len = 0; spin_lock(&capi_users_lock); for (cp = capi_users; cp ; cp = cp->next) { len += sprintf(page+len, "%s\n", cp->name); if (len <= off) { off -= len; len = 0; } else { if (len-off > count) goto endloop; } }endloop: spin_unlock(&capi_users_lock); *start = page+off; if (len < count) *eof = 1; if (len>count) len = count; if (len<0) len = 0; return len;}/* * /proc/capi/controller: * cnr driver cardstate name driverinfo */static int proc_controller_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ struct capi_ctr *cp; int i; int len = 0; for (i=0; i < CAPI_MAXCONTR; i++) { cp = &cards[i]; if (cp->cardstate == CARD_FREE) continue; len += sprintf(page+len, "%d %-10s %-8s %-16s %s\n", cp->cnr, cp->driver->name, cardstate2str(cp->cardstate), cp->name, cp->driver->procinfo ? cp->driver->procinfo(cp) : "" ); if (len <= off) { off -= len; len = 0; } else { if (len-off > count) goto endloop; } }endloop: *start = page+off; if (len < count) *eof = 1; if (len>count) len = count; if (len<0) len = 0; return len;}/* * /proc/capi/applstats: * applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt */static int proc_applstats_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ struct capi_appl *ap; int i; int len = 0; for (i=0; i < CAPI_MAXAPPL; i++) { ap = &applications[i]; if (ap->applid == 0) continue; len += sprintf(page+len, "%u %lu %lu %lu %lu\n", ap->applid, ap->nrecvctlpkt, ap->nrecvdatapkt, ap->nsentctlpkt, ap->nsentdatapkt); if (len <= off) { off -= len; len = 0; } else { if (len-off > count) goto endloop; } }endloop: *start = page+off; if (len < count) *eof = 1; if (len>count) len = count; if (len<0) len = 0; return len;}/* * /proc/capi/contrstats: * cnr nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt */static int proc_contrstats_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ struct capi_ctr *cp; int i; int len = 0; for (i=0; i < CAPI_MAXCONTR; i++) { cp = &cards[i]; if (cp->cardstate == CARD_FREE) continue; len += sprintf(page+len, "%d %lu %lu %lu %lu\n", cp->cnr, cp->nrecvctlpkt, cp->nrecvdatapkt, cp->nsentctlpkt, cp->nsentdatapkt); if (len <= off) { off -= len; len = 0; } else { if (len-off > count) goto endloop; } }endloop: *start = page+off; if (len < count) *eof = 1; if (len>count) len = count; if (len<0) len = 0; return len;}static struct procfsentries { char *name; mode_t mode; int (*read_proc)(char *page, char **start, off_t off, int count, int *eof, void *data); struct proc_dir_entry *procent;} procfsentries[] = { { "capi", S_IFDIR, 0 }, { "capi/applications", 0 , proc_applications_read_proc }, { "capi/ncci", 0 , proc_ncci_read_proc }, { "capi/driver", 0 , proc_driver_read_proc }, { "capi/users", 0 , proc_users_read_proc }, { "capi/controller", 0 , proc_controller_read_proc }, { "capi/applstats", 0 , proc_applstats_read_proc }, { "capi/contrstats", 0 , proc_contrstats_read_proc }, { "capi/drivers", S_IFDIR, 0 }, { "capi/controllers", S_IFDIR, 0 },};static void proc_capi_init(void){ int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); int i; for (i=0; i < nelem; i++) { struct procfsentries *p = procfsentries + i; p->procent = create_proc_entry(p->name, p->mode, 0); if (p->procent) p->procent->read_proc = p->read_proc; }}static void proc_capi_exit(void){ int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); int i; for (i=nelem-1; i >= 0; i--) { struct procfsentries *p = procfsentries + i; if (p->procent) { remove_proc_entry(p->name, 0); p->procent = 0; } }}/* -------- Notifier handling --------------------------------- */static struct capi_notifier_list{ struct capi_notifier *head; struct capi_notifier *tail;} notifier_list;static spinlock_t notifier_lock = SPIN_LOCK_UNLOCKED;static inline void notify_enqueue(struct capi_notifier *np){ struct capi_notifier_list *q = ¬ifier_list; unsigned long flags; spin_lock_irqsave(¬ifier_lock, flags); if (q->tail) { q->tail->next = np; q->tail = np; } else { q->head = q->tail = np; } spin_unlock_irqrestore(¬ifier_lock, flags);}static inline struct capi_notifier *notify_dequeue(void){ struct capi_notifier_list *q = ¬ifier_list; struct capi_notifier *np = 0; unsigned long flags; spin_lock_irqsave(¬ifier_lock, flags); if (q->head) { np = q->head; if ((q->head = np->next) == 0) q->tail = 0; np->next = 0; } spin_unlock_irqrestore(¬ifier_lock, flags); return np;}static int notify_push(unsigned int cmd, __u32 controller, __u16 applid, __u32 ncci){ struct capi_notifier *np; MOD_INC_USE_COUNT; np = (struct capi_notifier *)kmalloc(sizeof(struct capi_notifier), GFP_ATOMIC); if (!np) { MOD_DEC_USE_COUNT; return -1; } memset(np, 0, sizeof(struct capi_notifier)); np->cmd = cmd; np->controller = controller; np->applid = applid; np->ncci = ncci; notify_enqueue(np); /* * The notifier will result in adding/deleteing * of devices. Devices can only removed in * user process, not in bh. */ MOD_INC_USE_COUNT; if (schedule_task(&tq_state_notify) == 0) MOD_DEC_USE_COUNT; return 0;}/* -------- KCI_CONTRUP --------------------------------------- */static void notify_up(__u32 contr){ struct capi_interface_user *p; printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr); spin_lock(&capi_users_lock); for (p = capi_users; p; p = p->next) { if (!p->callback) continue; (*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile); } spin_unlock(&capi_users_lock);}/* -------- KCI_CONTRDOWN ------------------------------------- */static void notify_down(__u32 contr){ struct capi_interface_user *p; printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr); spin_lock(&capi_users_lock); for (p = capi_users; p; p = p->next) { if (!p->callback) continue; (*p->callback) (KCI_CONTRDOWN, contr, 0); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -