📄 kcapi.c
字号:
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); } spin_unlock(&capi_users_lock);}/* -------- KCI_NCCIUP ---------------------------------------- */static void notify_ncciup(__u32 contr, __u16 applid, __u32 ncci){ struct capi_interface_user *p; struct capi_ncciinfo n; n.applid = applid; n.ncci = ncci; /*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_NCCIUP, contr, &n); } spin_unlock(&capi_users_lock);};/* -------- KCI_NCCIDOWN -------------------------------------- */static void notify_nccidown(__u32 contr, __u16 applid, __u32 ncci){ struct capi_interface_user *p; struct capi_ncciinfo n; n.applid = applid; n.ncci = ncci; /*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_NCCIDOWN, contr, &n); } spin_unlock(&capi_users_lock);};/* ------------------------------------------------------------ */static void inline notify_doit(struct capi_notifier *np){ switch (np->cmd) { case KCI_CONTRUP: notify_up(np->controller); break; case KCI_CONTRDOWN: notify_down(np->controller); break; case KCI_NCCIUP: notify_ncciup(np->controller, np->applid, np->ncci); break; case KCI_NCCIDOWN: notify_nccidown(np->controller, np->applid, np->ncci); break; }}static void notify_handler(void *dummy){ struct capi_notifier *np; while ((np = notify_dequeue()) != 0) { notify_doit(np); kfree(np); MOD_DEC_USE_COUNT; } MOD_DEC_USE_COUNT;} /* -------- NCCI Handling ------------------------------------- */static inline void mq_init(struct capi_ncci * np){ int i; np->msgidqueue = 0; np->msgidlast = 0; np->nmsg = 0; memset(np->msgidpool, 0, sizeof(np->msgidpool)); np->msgidfree = &np->msgidpool[0]; for (i = 1; i < np->winsize; i++) { np->msgidpool[i].next = np->msgidfree; np->msgidfree = &np->msgidpool[i]; }}static inline int mq_enqueue(struct capi_ncci * np, __u16 msgid){ struct msgidqueue *mq; if ((mq = np->msgidfree) == 0) return 0; np->msgidfree = mq->next; mq->msgid = msgid; mq->next = 0; if (np->msgidlast) np->msgidlast->next = mq; np->msgidlast = mq; if (!np->msgidqueue) np->msgidqueue = mq; np->nmsg++; return 1;}static inline int mq_dequeue(struct capi_ncci * np, __u16 msgid){ struct msgidqueue **pp; for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) { if ((*pp)->msgid == msgid) { struct msgidqueue *mq = *pp; *pp = mq->next; if (mq == np->msgidlast) np->msgidlast = 0; mq->next = np->msgidfree; np->msgidfree = mq; np->nmsg--; return 1; } } return 0;}static void controllercb_appl_registered(struct capi_ctr * card, __u16 appl){}static void controllercb_appl_released(struct capi_ctr * card, __u16 appl){ struct capi_ncci **pp, **nextpp; for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) { if (NCCI2CTRL((*pp)->ncci) == card->cnr) { struct capi_ncci *np = *pp; *pp = np->next; printk(KERN_INFO "kcapi: appl %d ncci 0x%x down!\n", appl, np->ncci); kfree(np); APPL(appl)->nncci--; nextpp = pp; } else { nextpp = &(*pp)->next; } } APPL(appl)->releasing--; if (APPL(appl)->releasing <= 0) { APPL(appl)->signal = 0; APPL_MARK_FREE(appl); printk(KERN_INFO "kcapi: appl %d down\n", appl); }}/* * ncci managment */static void controllercb_new_ncci(struct capi_ctr * card, __u16 appl, __u32 ncci, __u32 winsize){ struct capi_ncci *np; if (!VALID_APPLID(appl)) { printk(KERN_ERR "avmb1_handle_new_ncci: illegal appl %d\n", appl); return; } if ((np = (struct capi_ncci *) kmalloc(sizeof(struct capi_ncci), GFP_ATOMIC)) == 0) { printk(KERN_ERR "capi_new_ncci: alloc failed ncci 0x%x\n", ncci); return; } if (winsize > CAPI_MAXDATAWINDOW) { printk(KERN_ERR "capi_new_ncci: winsize %d too big, set to %d\n", winsize, CAPI_MAXDATAWINDOW); winsize = CAPI_MAXDATAWINDOW; } np->applid = appl; np->ncci = ncci; np->winsize = winsize; mq_init(np); np->next = APPL(appl)->nccilist; APPL(appl)->nccilist = np; APPL(appl)->nncci++; printk(KERN_INFO "kcapi: appl %d ncci 0x%x up\n", appl, ncci); notify_push(KCI_NCCIUP, CARDNR(card), appl, ncci);}static void controllercb_free_ncci(struct capi_ctr * card, __u16 appl, __u32 ncci){ struct capi_ncci **pp; if (!VALID_APPLID(appl)) { printk(KERN_ERR "free_ncci: illegal appl %d\n", appl); return; } for (pp = &APPL(appl)->nccilist; *pp; pp = &(*pp)->next) { if ((*pp)->ncci == ncci) { struct capi_ncci *np = *pp; *pp = np->next; kfree(np); APPL(appl)->nncci--; printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", appl, ncci); notify_push(KCI_NCCIDOWN, CARDNR(card), appl, ncci); return; } } printk(KERN_ERR "free_ncci: ncci 0x%x not found\n", ncci);}static struct capi_ncci *find_ncci(struct capi_appl * app, __u32 ncci){ struct capi_ncci *np; for (np = app->nccilist; np; np = np->next) { if (np->ncci == ncci) return np; } return 0;}/* -------- Receiver ------------------------------------------ */static void recv_handler(void *dummy){ struct sk_buff *skb; while ((skb = skb_dequeue(&recv_queue)) != 0) { __u16 appl = CAPIMSG_APPID(skb->data); struct capi_ncci *np; if (!VALID_APPLID(appl)) { printk(KERN_ERR "kcapi: recv_handler: applid %d ? (%s)\n", appl, capi_message2str(skb->data)); kfree_skb(skb); continue; } if (APPL(appl)->signal == 0) { printk(KERN_ERR "kcapi: recv_handler: applid %d has no signal function\n", appl); kfree_skb(skb); continue; } if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3 && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF && (np = find_ncci(APPL(appl), CAPIMSG_NCCI(skb->data))) != 0 && mq_dequeue(np, CAPIMSG_MSGID(skb->data)) == 0) { printk(KERN_ERR "kcapi: msgid %hu ncci 0x%x not on queue\n", CAPIMSG_MSGID(skb->data), np->ncci); } if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3 && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) { APPL(appl)->nrecvdatapkt++; } else { APPL(appl)->nrecvctlpkt++; } skb_queue_tail(&APPL(appl)->recv_queue, skb); (APPL(appl)->signal) (APPL(appl)->applid, APPL(appl)->param); }}static void controllercb_handle_capimsg(struct capi_ctr * card, __u16 appl, struct sk_buff *skb){ int showctl = 0; __u8 cmd, subcmd; 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)); } } skb_queue_tail(&recv_queue, skb); queue_task(&tq_recv_notify, &tq_immediate); mark_bh(IMMEDIATE_BH); return;error: kfree_skb(skb);}static void controllercb_ready(struct capi_ctr * card){ __u16 appl; card->cardstate = CARD_RUNNING; for (appl = 1; appl <= CAPI_MAXAPPL; appl++) { if (!VALID_APPLID(appl)) continue; if (APPL(appl)->releasing) continue; card->driver->register_appl(card, appl, &APPL(appl)->rparam); } printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n", CARDNR(card), card->name); notify_push(KCI_CONTRUP, CARDNR(card), 0, 0);}static void controllercb_reseted(struct capi_ctr * card){ __u16 appl; if (card->cardstate == CARD_FREE) return; 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 capi_ncci **pp, **nextpp; for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) { if (NCCI2CTRL((*pp)->ncci) == card->cnr) { struct capi_ncci *np = *pp; *pp = np->next; printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down!\n", appl, np->ncci); notify_push(KCI_NCCIDOWN, CARDNR(card), appl, np->ncci); kfree(np); nextpp = pp; } else { nextpp = &(*pp)->next; } } } printk(KERN_NOTICE "kcapi: card %d down.\n", CARDNR(card)); notify_push(KCI_CONTRDOWN, CARDNR(card), 0, 0);}static void controllercb_suspend_output(struct capi_ctr *card){ if (!card->blocked) { printk(KERN_DEBUG "kcapi: card %d suspend\n", CARDNR(card)); card->blocked = 1; }}static void controllercb_resume_output(struct capi_ctr *card){ if (card->blocked) { printk(KERN_DEBUG "kcapi: card %d resume\n", CARDNR(card)); card->blocked = 0; }}/* ------------------------------------------------------------- */struct capi_ctr *drivercb_attach_ctr(struct capi_driver *driver, char *name, void *driverdata){ struct capi_ctr *card, **pp; int i; for (i=0; i < CAPI_MAXCONTR && cards[i].cardstate != CARD_FREE; i++) ; if (i == CAPI_MAXCONTR) { printk(KERN_ERR "kcapi: out of controller slots\n"); return 0; } card = &cards[i]; memset(card, 0, sizeof(struct capi_ctr)); card->driver = driver; card->cnr = CARDNR(card); strncpy(card->name, name, sizeof(card->name)); card->cardstate = CARD_DETECTED; card->blocked = 0; card->driverdata = driverdata; card->traceflag = showcapimsgs; card->ready = controllercb_ready; card->reseted = controllercb_reseted; card->suspend_output = controllercb_suspend_output; card->resume_output = controllercb_resume_output; card->handle_capimsg = controllercb_handle_capimsg; card->appl_registered = controllercb_appl_registered; card->appl_released = controllercb_appl_released; card->new_ncci = controllercb_new_ncci; card->free_ncci = controllercb_free_ncci; for (pp = &driver->controller; *pp; pp = &(*pp)->next) ; card->next = 0; *pp = card; driver->ncontroller++; sprintf(card->procfn, "capi/controllers/%d", card->cnr); card->procent = create_proc_entry(card->procfn, 0, 0); if (card->procent) { card->procent->read_proc = (int (*)(char *,char **,off_t,int,int *,void *)) driver->ctr_read_proc; card->procent->data = card; } ncards++; printk(KERN_NOTICE "kcapi: Controller %d: %s attached\n", card->cnr, card->name); return card;}static int drivercb_detach_ctr(struct capi_ctr *card){ struct capi_driver *driver = card->driver; struct capi_ctr **pp; if (card->cardstate == CARD_FREE) return 0; if (card->cardstate != CARD_DETECTED) controllercb_reseted(card); for (pp = &driver->controller; *pp ; pp = &(*pp)->next) { if (*pp == card) { *pp = card->next; driver->ncontroller--; ncards--; break; } } if (card->procent) { remove_proc_entry(card->procfn, 0); card->procent = 0; } card->cardstate = CARD_FREE; printk(KERN_NOTICE "kcapi: Controller %d: %s unregistered\n", card->cnr, card->name); return 0;}/* ------------------------------------------------------------- *//* fallback if no driver read_proc function defined by driver */static int driver_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ struct capi_driver *driver = (struct capi_driver *)data; int len = 0; len += sprintf(page+len, "%-16s %s\n", "name", driver->name); len += sprintf(page+len, "%-16s %s\n", "revision", driver->revision); if (len < off) return 0; *eof = 1; *start = page + off; return ((count < len-off) ? count : len-off);}/* ------------------------------------------------------------- */static struct capi_driver_interface di = { drivercb_attach_ctr, drivercb_detach_ctr,};struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver){ struct capi_driver **pp; MOD_INC_USE_COUNT; spin_lock(&drivers_lock); for (pp = &drivers; *pp; pp = &(*pp)->next) ; driver->next = 0; *pp = driver; spin_unlock(&drivers_lock); printk(KERN_NOTICE "kcapi: driver %s attached\n", driver->name); sprintf(driver->procfn, "capi/drivers/%s", driver->name); driver->procent = create_proc_entry(driver->procfn, 0, 0); if (driver->procent) { if (driver->driver_read_proc) { driver->procent->read_proc = (int (*)(char *,char **,off_t,int,int *,void *)) driver->driver_read_proc; } else { driver->procent->read_proc = driver_read_proc; } driver->procent->data = driver; } return &di;}void detach_capi_driver(struct capi_driver *driver){ struct capi_driver **pp; spin_lock(&drivers_lock); for (pp = &drivers; *pp && *pp != driver; pp = &(*pp)->next) ; if (*pp) { *pp = (*pp)->next; printk(KERN_NOTICE "kcapi: driver %s detached\n", driver->name); } else { printk(KERN_ERR "kcapi: driver %s double detach ?\n", driver->name); } spin_unlock(&drivers_lock); if (driver->procent) { remove_proc_entry(driver->procfn, 0); driver->procent = 0; } MOD_DEC_USE_COUNT;}/* ------------------------------------------------------------- *//* -------- CAPI2.0 Interface ---------------------------------- *//* ------------------------------------------------------------- */static __u16 capi_isinstalled(void){ int i; for (i = 0; i < CAPI_MAXCONTR; i++) { if (cards[i].cardstate == CARD_RUNNING) return CAPI_NOERROR; } return CAPI_REGNOTINSTALLED;}static __u16 capi_register(capi_register_params * rparam, __u16 * applidp){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -