capi.c
来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 1,731 行 · 第 1/3 页
C
1,731 行
skb = mp->ttyskb; if (skb) { if (skb_tailroom(skb) > 0) { *(skb_put(skb, 1)) = ch; return; } mp->ttyskb = 0; skb_queue_tail(&mp->outqueue, skb); mp->outbytes += skb->len; (void)handle_minor_send(mp); } skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+CAPI_MAX_BLKSIZE, GFP_ATOMIC); if (skb) { skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); *(skb_put(skb, 1)) = ch; mp->ttyskb = skb; } else { printk(KERN_ERR "capinc_put_char: char %u lost\n", ch); }}static void capinc_tty_flush_chars(struct tty_struct *tty){ struct capiminor *mp = (struct capiminor *)tty->driver_data; struct sk_buff *skb;#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_flush_chars\n");#endif if (!mp || !mp->nccip) {#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_flush_chars: mp or mp->ncci NULL\n");#endif return; } skb = mp->ttyskb; if (skb) { mp->ttyskb = 0; skb_queue_tail(&mp->outqueue, skb); mp->outbytes += skb->len; (void)handle_minor_send(mp); } (void)handle_minor_recv(mp);}static int capinc_tty_write_room(struct tty_struct *tty){ struct capiminor *mp = (struct capiminor *)tty->driver_data; int room; if (!mp || !mp->nccip) {#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_write_room: mp or mp->ncci NULL\n");#endif return 0; } room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue); room *= CAPI_MAX_BLKSIZE;#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_write_room = %d\n", room);#endif return room;}int capinc_tty_chars_in_buffer(struct tty_struct *tty){ struct capiminor *mp = (struct capiminor *)tty->driver_data; if (!mp || !mp->nccip) {#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_chars_in_buffer: mp or mp->ncci NULL\n");#endif return 0; }#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n", mp->outbytes, mp->nack, skb_queue_len(&mp->outqueue), skb_queue_len(&mp->inqueue));#endif return mp->outbytes;}static int capinc_tty_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg){ int error = 0; switch (cmd) { default: error = n_tty_ioctl (tty, file, cmd, arg); break; } return error;}static void capinc_tty_set_termios(struct tty_struct *tty, struct termios * old){#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_set_termios\n");#endif}static void capinc_tty_throttle(struct tty_struct * tty){ struct capiminor *mp = (struct capiminor *)tty->driver_data;#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_throttle\n");#endif if (mp) mp->ttyinstop = 1;}static void capinc_tty_unthrottle(struct tty_struct * tty){ struct capiminor *mp = (struct capiminor *)tty->driver_data;#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_unthrottle\n");#endif if (mp) { mp->ttyinstop = 0; handle_minor_recv(mp); }}static void capinc_tty_stop(struct tty_struct *tty){ struct capiminor *mp = (struct capiminor *)tty->driver_data;#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_stop\n");#endif if (mp) { mp->ttyoutstop = 1; }}static void capinc_tty_start(struct tty_struct *tty){ struct capiminor *mp = (struct capiminor *)tty->driver_data;#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_start\n");#endif if (mp) { mp->ttyoutstop = 0; (void)handle_minor_send(mp); }}static void capinc_tty_hangup(struct tty_struct *tty){#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_hangup\n");#endif}static void capinc_tty_break_ctl(struct tty_struct *tty, int state){#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_break_ctl(%d)\n", state);#endif}static void capinc_tty_flush_buffer(struct tty_struct *tty){#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_flush_buffer\n");#endif}static void capinc_tty_set_ldisc(struct tty_struct *tty){#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_set_ldisc\n");#endif}static void capinc_tty_send_xchar(struct tty_struct *tty, char ch){#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_send_xchar(%d)\n", ch);#endif}static int capinc_tty_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ return 0;}#define CAPINC_NR_PORTS 256static struct tty_driver capinc_tty_driver;static int capinc_tty_refcount;static struct tty_struct *capinc_tty_table[CAPINC_NR_PORTS];static struct termios *capinc_tty_termios[CAPINC_NR_PORTS];static struct termios *capinc_tty_termios_locked[CAPINC_NR_PORTS];static int capinc_tty_init(void){ struct tty_driver *drv = &capinc_tty_driver; /* Initialize the tty_driver structure */ memset(drv, 0, sizeof(struct tty_driver)); drv->magic = TTY_DRIVER_MAGIC;#if (LINUX_VERSION_CODE > 0x20100) drv->driver_name = "capi_nc";#endif drv->name = "capi/%d"; drv->major = capi_ttymajor; drv->minor_start = 0; drv->num = CAPINC_NR_PORTS; drv->type = TTY_DRIVER_TYPE_SERIAL; drv->subtype = SERIAL_TYPE_NORMAL; drv->init_termios = tty_std_termios; drv->init_termios.c_iflag = ICRNL; drv->init_termios.c_oflag = OPOST | ONLCR; drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; drv->init_termios.c_lflag = 0; drv->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_RESET_TERMIOS; drv->refcount = &capinc_tty_refcount; drv->table = capinc_tty_table; drv->termios = capinc_tty_termios; drv->termios_locked = capinc_tty_termios_locked; drv->open = capinc_tty_open; drv->close = capinc_tty_close; drv->write = capinc_tty_write; drv->put_char = capinc_tty_put_char; drv->flush_chars = capinc_tty_flush_chars; drv->write_room = capinc_tty_write_room; drv->chars_in_buffer = capinc_tty_chars_in_buffer; drv->ioctl = capinc_tty_ioctl; drv->set_termios = capinc_tty_set_termios; drv->throttle = capinc_tty_throttle; drv->unthrottle = capinc_tty_unthrottle; drv->stop = capinc_tty_stop; drv->start = capinc_tty_start; drv->hangup = capinc_tty_hangup;#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ drv->break_ctl = capinc_tty_break_ctl;#endif drv->flush_buffer = capinc_tty_flush_buffer; drv->set_ldisc = capinc_tty_set_ldisc;#if (LINUX_VERSION_CODE >= 131343) drv->send_xchar = capinc_tty_send_xchar; drv->read_proc = capinc_tty_read_proc;#endif if (tty_register_driver(drv)) { printk(KERN_ERR "Couldn't register capi_nc driver\n"); return -1; } return 0;}static void capinc_tty_exit(void){ struct tty_driver *drv = &capinc_tty_driver; int retval; if ((retval = tty_unregister_driver(drv))) printk(KERN_ERR "capi: failed to unregister capi_nc driver (%d)\n", retval);}#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE *//* -------- /proc functions ----------------------------------------- *//* * /proc/capi/capi20: * minor applid nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt */static int proc_capidev_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ struct capidev *cdev; struct list_head *l; int len = 0; read_lock(&capidev_list_lock); list_for_each(l, &capidev_list) { cdev = list_entry(l, struct capidev, list); len += sprintf(page+len, "0 %d %lu %lu %lu %lu\n", cdev->applid, cdev->nrecvctlpkt, cdev->nrecvdatapkt, cdev->nsentctlpkt, cdev->nsentdatapkt); if (len <= off) { off -= len; len = 0; } else { if (len-off > count) goto endloop; } }endloop: read_unlock(&capidev_list_lock); if (len < count) *eof = 1; if (len > count) len = count; if (len < 0) len = 0; return len;}/* * /proc/capi/capi20ncci: * applid ncci */static int proc_capincci_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ struct capidev *cdev; struct capincci *np; struct list_head *l; int len = 0; read_lock(&capidev_list_lock); list_for_each(l, &capidev_list) { cdev = list_entry(l, struct capidev, list); for (np=cdev->nccis; np; np = np->next) { len += sprintf(page+len, "%d 0x%x\n", cdev->applid, np->ncci); if (len <= off) { off -= len; len = 0; } else { if (len-off > count) goto endloop; } } }endloop: read_unlock(&capidev_list_lock); *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/capi20", 0 , proc_capidev_read_proc }, { "capi/capi20ncci", 0 , proc_capincci_read_proc },};static void __init proc_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 __exit proc_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; } }}/* -------- init function and module interface ---------------------- */static void alloc_exit(void){ if (capidev_cachep) { (void)kmem_cache_destroy(capidev_cachep); capidev_cachep = 0; } if (capincci_cachep) { (void)kmem_cache_destroy(capincci_cachep); capincci_cachep = 0; }#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE if (capidh_cachep) { (void)kmem_cache_destroy(capidh_cachep); capidh_cachep = 0; } if (capiminor_cachep) { (void)kmem_cache_destroy(capiminor_cachep); capiminor_cachep = 0; }#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */}static int __init alloc_init(void){ capidev_cachep = kmem_cache_create("capi20_dev", sizeof(struct capidev), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!capidev_cachep) { alloc_exit(); return -ENOMEM; } capincci_cachep = kmem_cache_create("capi20_ncci", sizeof(struct capincci), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!capincci_cachep) { alloc_exit(); return -ENOMEM; }#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE capidh_cachep = kmem_cache_create("capi20_dh", sizeof(struct datahandle_queue), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!capidh_cachep) { alloc_exit(); return -ENOMEM; } capiminor_cachep = kmem_cache_create("capi20_minor", sizeof(struct capiminor), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!capiminor_cachep) { alloc_exit(); return -ENOMEM; }#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ return 0;}static void lower_callback(unsigned int cmd, u32 contr, void *data){ struct capi_ncciinfo *np; struct capidev *cdev; switch (cmd) { case KCI_CONTRUP: printk(KERN_INFO "capi: controller %hu up\n", contr); break; case KCI_CONTRDOWN: printk(KERN_INFO "capi: controller %hu down\n", contr); break; case KCI_NCCIUP: np = (struct capi_ncciinfo *)data; if ((cdev = capidev_find(np->applid)) == 0) return; (void)capincci_alloc(cdev, np->ncci); break; case KCI_NCCIDOWN: np = (struct capi_ncciinfo *)data; if ((cdev = capidev_find(np->applid)) == 0) return; (void)capincci_free(cdev, np->ncci); break; }}static struct capi_interface_user cuser = { name: "capi20", callback: lower_callback,};static char rev[32];static int __init capi_init(void){ char *p; char *compileinfo; MOD_INC_USE_COUNT; if ((p = strchr(revision, ':')) != 0 && p[1]) { strncpy(rev, p + 2, sizeof(rev)); rev[sizeof(rev)-1] = 0; if ((p = strchr(rev, '$')) != 0 && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); if (devfs_register_chrdev(capi_major, "capi20", &capi_fops)) { printk(KERN_ERR "capi20: unable to get major %d\n", capi_major); MOD_DEC_USE_COUNT; return -EIO; } devfs_register (NULL, "isdn/capi20", DEVFS_FL_DEFAULT, capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR, &capi_fops, NULL); printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major); if ((capifuncs = attach_capi_interface(&cuser)) == 0) { MOD_DEC_USE_COUNT; devfs_unregister_chrdev(capi_major, "capi20"); devfs_unregister(devfs_find_handle(NULL, "capi20", capi_major, 0, DEVFS_SPECIAL_CHR, 0)); return -EIO; }#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE if (capinc_tty_init() < 0) { (void) detach_capi_interface(&cuser); devfs_unregister_chrdev(capi_major, "capi20"); MOD_DEC_USE_COUNT; return -ENOMEM; }#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ if (alloc_init() < 0) {#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE capinc_tty_exit();#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ (void) detach_capi_interface(&cuser); devfs_unregister_chrdev(capi_major, "capi20"); devfs_unregister(devfs_find_handle(NULL, "capi20", capi_major, 0, DEVFS_SPECIAL_CHR, 0)); MOD_DEC_USE_COUNT; return -ENOMEM; } (void)proc_init();#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) compileinfo = " (middleware+capifs)";#else compileinfo = " (no capifs)";#endif#else compileinfo = " (no middleware)";#endif printk(KERN_NOTICE "capi20: Rev %s: started up with major %d%s\n", rev, capi_major, compileinfo); MOD_DEC_USE_COUNT; return 0;}static void __exit capi_exit(void){ alloc_exit(); (void)proc_exit(); devfs_unregister_chrdev(capi_major, "capi20"); devfs_unregister(devfs_find_handle(NULL, "isdn/capi20", capi_major, 0, DEVFS_SPECIAL_CHR, 0));#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE capinc_tty_exit();#endif (void) detach_capi_interface(&cuser); printk(KERN_NOTICE "capi: Rev %s: unloaded\n", rev);}module_init(capi_init);module_exit(capi_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?