📄 kcapi.c
字号:
/* * $Id: kcapi.c,v 1.21.6.1 2000/12/10 23:39:19 kai Exp $ * * Kernel CAPI 2.0 Module * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: kcapi.c,v $ * Revision 1.21.6.1 2000/12/10 23:39:19 kai * in 2.4 we don't have tq_scheduler anymore. * also add one supported card to hfc_pci.c * (from main branch) * * Revision 1.21 2000/11/23 20:45:14 kai * fixed module_init/exit stuff * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. * * Revision 1.20 2000/11/19 17:01:53 kai * compatibility cleanup - part 2 * * Revision 1.19 2000/11/01 14:05:02 calle * - use module_init/module_exit from linux/init.h. * - all static struct variables are initialized with "membername:" now. * - avm_cs.c, let it work with newer pcmcia-cs. * * Revision 1.18 2000/07/20 10:22:27 calle * - Made procfs function cleaner and removed variable "begin". * * Revision 1.17 2000/04/21 13:00:56 calle * Bugfix: driver_proc_info was also wrong. * * Revision 1.16 2000/04/21 12:38:42 calle * Bugfix: error in proc_ functions, begin-off => off-begin * * Revision 1.15 2000/04/06 15:01:25 calle * Bugfix: crash in capidrv.c when reseting a capi controller. * - changed code order on remove of controller. * - using tq_schedule for notifier in kcapi.c. * - now using spin_lock_irqsave() and spin_unlock_irqrestore(). * strange: sometimes even MP hang on unload of isdn.o ... * * Revision 1.14 2000/04/03 13:29:25 calle * make Tim Waugh happy (module unload races in 2.3.99-pre3). * no real problem there, but now it is much cleaner ... * * Revision 1.13 2000/03/03 15:50:42 calle * - kernel CAPI: * - Changed parameter "param" in capi_signal from __u32 to void *. * - rewrote notifier handling in kcapi.c * - new notifier NCCI_UP and NCCI_DOWN * - User CAPI: * - /dev/capi20 is now a cloning device. * - middleware extentions prepared. * - capidrv.c * - locking of list operations and module count updates. * * Revision 1.12 2000/01/28 16:45:39 calle * new manufacturer command KCAPI_CMD_ADDCARD (generic addcard), * will search named driver and call the add_card function if one exist. * * Revision 1.11 1999/11/23 13:29:29 calle * Bugfix: incoming capi message were never traced. * * Revision 1.10 1999/10/26 15:30:32 calle * Generate error message if user want to add card, but driver module is * not loaded. * * Revision 1.9 1999/10/11 22:04:12 keil * COMPAT_NEED_UACCESS (no include in isdn_compat.h) * * Revision 1.8 1999/09/10 17:24:18 calle * Changes for proposed standard for CAPI2.0: * - AK148 "Linux Exention" * * Revision 1.7 1999/09/04 06:20:05 keil * Changes from kernel set_current_state() * * Revision 1.6 1999/07/20 06:41:49 calle * Bugfix: After the redesign of the AVM B1 driver, the driver didn't even * compile, if not selected as modules. * * Revision 1.5 1999/07/09 15:05:48 keil * compat.h is now isdn_compat.h * * Revision 1.4 1999/07/08 14:15:17 calle * Forgot to count down ncards in drivercb_detach_ctr. * * Revision 1.3 1999/07/06 07:42:02 calle * - changes in /proc interface * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb. * * Revision 1.2 1999/07/05 15:09:52 calle * - renamed "appl_release" to "appl_released". * - version und profile data now cleared on controller reset * - extended /proc interface, to allow driver and controller specific * informations to include by driver hackers. * * Revision 1.1 1999/07/01 15:26:42 calle * complete new version (I love it): * + new hardware independed "capi_driver" interface that will make it easy to: * - support other controllers with CAPI-2.0 (i.e. USB Controller) * - write a CAPI-2.0 for the passive cards * - support serial link CAPI-2.0 boxes. * + wrote "capi_driver" for all supported cards. * + "capi_driver" (supported cards) now have to be configured with * make menuconfig, in the past all supported cards where included * at once. * + new and better informations in /proc/capi/ * + new ioctl to switch trace of capi messages per controller * using "avmcapictrl trace [contr] on|off|...." * + complete testcircle with all supported cards and also the * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. * */#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.21.6.1 $";/* ------------------------------------------------------------- */#define CARD_FREE 0#define CARD_DETECTED 1#define CARD_LOADING 2#define CARD_RUNNING 3/* ------------------------------------------------------------- */int showcapimsgs = 0;MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");MODULE_PARM(showcapimsgs, "0-4i");/* ------------------------------------------------------------- */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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -