📄 kcapi.c
字号:
u16 capi20_register(struct capi20_appl *ap){ int i; u16 applid; unsigned long flags; DBG(""); if (ap->rparam.datablklen < 128) return CAPI_LOGBLKSIZETOSMALL; write_lock_irqsave(&application_lock, flags); for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { if (capi_applications[applid - 1] == NULL) break; } if (applid > CAPI_MAXAPPL) { write_unlock_irqrestore(&application_lock, flags); return CAPI_TOOMANYAPPLS; } ap->applid = applid; capi_applications[applid - 1] = ap; ap->nrecvctlpkt = 0; ap->nrecvdatapkt = 0; ap->nsentctlpkt = 0; ap->nsentdatapkt = 0; ap->callback = NULL; init_MUTEX(&ap->recv_sem); skb_queue_head_init(&ap->recv_queue); INIT_WORK(&ap->recv_work, recv_handler, (void *)ap); ap->release_in_progress = 0; write_unlock_irqrestore(&application_lock, flags); down(&controller_sem); for (i = 0; i < CAPI_MAXCONTR; i++) { if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING) continue; register_appl(capi_cards[i], applid, &ap->rparam); } up(&controller_sem); if (showcapimsgs & 1) { printk(KERN_DEBUG "kcapi: appl %d up\n", applid); } return CAPI_NOERROR;}EXPORT_SYMBOL(capi20_register);u16 capi20_release(struct capi20_appl *ap){ int i; unsigned long flags; DBG("applid %#x", ap->applid); write_lock_irqsave(&application_lock, flags); ap->release_in_progress = 1; capi_applications[ap->applid - 1] = NULL; write_unlock_irqrestore(&application_lock, flags); down(&controller_sem); for (i = 0; i < CAPI_MAXCONTR; i++) { if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING) continue; release_appl(capi_cards[i], ap->applid); } up(&controller_sem); flush_scheduled_work(); skb_queue_purge(&ap->recv_queue); if (showcapimsgs & 1) { printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid); } return CAPI_NOERROR;}EXPORT_SYMBOL(capi20_release);u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb){ struct capi_ctr *card; int showctl = 0; u8 cmd, subcmd; DBG("applid %#x", ap->applid); if (ncards == 0) return CAPI_REGNOTINSTALLED; if ((ap->applid == 0) || ap->release_in_progress) return CAPI_ILLAPPNR; if (skb->len < 12 || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data)) || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data))) return CAPI_ILLCMDORSUBCMDORMSGTOSMALL; card = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data)); if (!card || card->cardstate != CARD_RUNNING) { card = get_capi_ctr_by_nr(1); // XXX why? if (!card || card->cardstate != CARD_RUNNING) return CAPI_REGNOTINSTALLED; } if (card->blocked) return CAPI_SENDQUEUEFULL; cmd = CAPIMSG_COMMAND(skb->data); subcmd = CAPIMSG_SUBCOMMAND(skb->data); if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) { card->nsentdatapkt++; ap->nsentdatapkt++; if (card->traceflag > 2) showctl |= 2; } else { card->nsentctlpkt++; ap->nsentctlpkt++; if (card->traceflag) showctl |= 2; } showctl |= (card->traceflag & 1); if (showctl & 2) { if (showctl & 1) { printk(KERN_DEBUG "kcapi: put [%#x] id#%d %s len=%u\n", CAPIMSG_CONTROLLER(skb->data), CAPIMSG_APPID(skb->data), capi_cmd2str(cmd, subcmd), CAPIMSG_LEN(skb->data)); } else { printk(KERN_DEBUG "kcapi: put [%#x] %s\n", CAPIMSG_CONTROLLER(skb->data), capi_message2str(skb->data)); } } return card->send_message(card, skb);}EXPORT_SYMBOL(capi20_put_message);u16 capi20_get_manufacturer(u32 contr, u8 *buf){ struct capi_ctr *card; if (contr == 0) { strlcpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN); return CAPI_NOERROR; } card = get_capi_ctr_by_nr(contr); if (!card || card->cardstate != CARD_RUNNING) return CAPI_REGNOTINSTALLED; strlcpy(buf, card->manu, CAPI_MANUFACTURER_LEN); return CAPI_NOERROR;}EXPORT_SYMBOL(capi20_get_manufacturer);u16 capi20_get_version(u32 contr, struct capi_version *verp){ struct capi_ctr *card; if (contr == 0) { *verp = driver_version; return CAPI_NOERROR; } card = get_capi_ctr_by_nr(contr); if (!card || card->cardstate != CARD_RUNNING) return CAPI_REGNOTINSTALLED; memcpy((void *) verp, &card->version, sizeof(capi_version)); return CAPI_NOERROR;}EXPORT_SYMBOL(capi20_get_version);u16 capi20_get_serial(u32 contr, u8 *serial){ struct capi_ctr *card; if (contr == 0) { strlcpy(serial, driver_serial, CAPI_SERIAL_LEN); return CAPI_NOERROR; } card = get_capi_ctr_by_nr(contr); if (!card || card->cardstate != CARD_RUNNING) return CAPI_REGNOTINSTALLED; strlcpy((void *) serial, card->serial, CAPI_SERIAL_LEN); return CAPI_NOERROR;}EXPORT_SYMBOL(capi20_get_serial);u16 capi20_get_profile(u32 contr, struct capi_profile *profp){ struct capi_ctr *card; if (contr == 0) { profp->ncontroller = ncards; return CAPI_NOERROR; } card = get_capi_ctr_by_nr(contr); if (!card || card->cardstate != CARD_RUNNING) return CAPI_REGNOTINSTALLED; memcpy((void *) profp, &card->profile, sizeof(struct capi_profile)); return CAPI_NOERROR;}EXPORT_SYMBOL(capi20_get_profile);#ifdef CONFIG_AVMB1_COMPATstatic int old_capi_manufacturer(unsigned int cmd, void __user *data){ avmb1_loadandconfigdef ldef; avmb1_extcarddef cdef; avmb1_resetdef rdef; capicardparams cparams; struct capi_ctr *card; struct capi_driver *driver = NULL; capiloaddata ldata; struct list_head *l; unsigned long flags; int retval; switch (cmd) { case AVMB1_ADDCARD: case AVMB1_ADDCARD_WITH_TYPE: if (cmd == AVMB1_ADDCARD) { if ((retval = copy_from_user(&cdef, data, sizeof(avmb1_carddef)))) return retval; cdef.cardtype = AVM_CARDTYPE_B1; } else { if ((retval = copy_from_user(&cdef, data, sizeof(avmb1_extcarddef)))) return retval; } cparams.port = cdef.port; cparams.irq = cdef.irq; cparams.cardnr = cdef.cardnr; read_lock_irqsave(&capi_drivers_list_lock, flags); switch (cdef.cardtype) { case AVM_CARDTYPE_B1: list_for_each(l, &capi_drivers) { driver = list_entry(l, struct capi_driver, list); if (strcmp(driver->name, "b1isa") == 0) break; } break; case AVM_CARDTYPE_T1: list_for_each(l, &capi_drivers) { driver = list_entry(l, struct capi_driver, list); if (strcmp(driver->name, "t1isa") == 0) break; } break; default: driver = NULL; break; } if (!driver) { read_unlock_irqrestore(&capi_drivers_list_lock, flags); printk(KERN_ERR "kcapi: driver not loaded.\n"); return -EIO; } if (!driver->add_card) { read_unlock_irqrestore(&capi_drivers_list_lock, flags); printk(KERN_ERR "kcapi: driver has no add card function.\n"); return -EIO; } retval = driver->add_card(driver, &cparams); read_unlock_irqrestore(&capi_drivers_list_lock, flags); return retval; case AVMB1_LOAD: case AVMB1_LOAD_AND_CONFIG: if (cmd == AVMB1_LOAD) { if (copy_from_user(&ldef, data, sizeof(avmb1_loaddef))) return -EFAULT; ldef.t4config.len = 0; ldef.t4config.data = NULL; } else { if (copy_from_user(&ldef, data, sizeof(avmb1_loadandconfigdef))) return -EFAULT; } card = get_capi_ctr_by_nr(ldef.contr); card = capi_ctr_get(card); if (!card) return -ESRCH; if (card->load_firmware == 0) { printk(KERN_DEBUG "kcapi: load: no load function\n"); return -ESRCH; } if (ldef.t4file.len <= 0) { printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len); return -EINVAL; } if (ldef.t4file.data == 0) { printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n"); return -EINVAL; } ldata.firmware.user = 1; ldata.firmware.data = ldef.t4file.data; ldata.firmware.len = ldef.t4file.len; ldata.configuration.user = 1; ldata.configuration.data = ldef.t4config.data; ldata.configuration.len = ldef.t4config.len; if (card->cardstate != CARD_DETECTED) { printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr); return -EBUSY; } card->cardstate = CARD_LOADING; retval = card->load_firmware(card, &ldata); if (retval) { card->cardstate = CARD_DETECTED; capi_ctr_put(card); return retval; } while (card->cardstate != CARD_RUNNING) { msleep_interruptible(100); /* 0.1 sec */ if (signal_pending(current)) { capi_ctr_put(card); return -EINTR; } } capi_ctr_put(card); return 0; case AVMB1_RESETCARD: if (copy_from_user(&rdef, data, sizeof(avmb1_resetdef))) return -EFAULT; card = get_capi_ctr_by_nr(rdef.contr); if (!card) return -ESRCH; if (card->cardstate == CARD_DETECTED) return 0; card->reset_ctr(card); while (card->cardstate > CARD_DETECTED) { msleep_interruptible(100); /* 0.1 sec */ if (signal_pending(current)) return -EINTR; } return 0; } return -EINVAL;}#endifint capi20_manufacturer(unsigned int cmd, void __user *data){ struct capi_ctr *card; switch (cmd) {#ifdef CONFIG_AVMB1_COMPAT case AVMB1_LOAD: case AVMB1_LOAD_AND_CONFIG: case AVMB1_RESETCARD: case AVMB1_GET_CARDINFO: case AVMB1_REMOVECARD: return old_capi_manufacturer(cmd, data);#endif case KCAPI_CMD_TRACE: { kcapi_flagdef fdef; if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef))) return -EFAULT; card = get_capi_ctr_by_nr(fdef.contr); if (!card) return -ESRCH; card->traceflag = fdef.flag; printk(KERN_INFO "kcapi: contr %d set trace=%d\n", card->cnr, card->traceflag); return 0; } case KCAPI_CMD_ADDCARD: { struct list_head *l; struct capi_driver *driver = NULL; capicardparams cparams; kcapi_carddef cdef; int retval; if ((retval = copy_from_user(&cdef, data, sizeof(cdef)))) return retval; cparams.port = cdef.port; cparams.irq = cdef.irq; cparams.membase = cdef.membase; cparams.cardnr = cdef.cardnr; cparams.cardtype = 0; cdef.driver[sizeof(cdef.driver)-1] = 0; list_for_each(l, &capi_drivers) { driver = list_entry(l, struct capi_driver, list); if (strcmp(driver->name, cdef.driver) == 0) break; } if (driver == 0) { printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n", cdef.driver); return -ESRCH; } if (!driver->add_card) { printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver); return -EIO; } return driver->add_card(driver, &cparams); } default: printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n", cmd); break; } return -EINVAL;}EXPORT_SYMBOL(capi20_manufacturer);/* temporary hack */void capi20_set_callback(struct capi20_appl *ap, void (*callback) (unsigned int cmd, __u32 contr, void *data)){ ap->callback = callback;}EXPORT_SYMBOL(capi20_set_callback);/* ------------------------------------------------------------- *//* -------- Init & Cleanup ------------------------------------- *//* ------------------------------------------------------------- *//* * init / exit functions */static int __init kcapi_init(void){ char *p; char rev[32]; kcapi_proc_init(); if ((p = strchr(revision, ':')) != 0 && p[1]) { strlcpy(rev, p + 2, sizeof(rev)); if ((p = strchr(rev, '$')) != 0 && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); printk(KERN_NOTICE "CAPI Subsystem Rev %s\n", rev); return 0;}static void __exit kcapi_exit(void){ kcapi_proc_exit(); /* make sure all notifiers are finished */ flush_scheduled_work();}module_init(kcapi_init);module_exit(kcapi_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -