📄 capi.c
字号:
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;}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;}void capinc_tty_set_termios(struct tty_struct *tty, struct termios * old){#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_set_termios\n");#endif}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;}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); }}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; }}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); }}void capinc_tty_hangup(struct tty_struct *tty){#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_hangup\n");#endif}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}void capinc_tty_flush_buffer(struct tty_struct *tty){#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_flush_buffer\n");#endif}void capinc_tty_set_ldisc(struct tty_struct *tty){#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_set_ldisc\n");#endif}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}int capinc_tty_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ return 0;}int capinc_write_proc(struct file *file, const char *buffer, unsigned long count, 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];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;}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; int len = 0; for (cdev=capidev_openlist; cdev; cdev = cdev->next) { len += sprintf(page+len, "%d %d %lu %lu %lu %lu\n", cdev->minor, 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: 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; int len = 0; for (cdev=capidev_openlist; cdev; cdev = cdev->next) { for (np=cdev->nccis; np; np = np->next) { len += sprintf(page+len, "%d 0x%x%s\n", cdev->applid, np->ncci,#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE "");#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */ np->minorp && np->minorp->file ? " open" : "");#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ 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/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 __exit 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[10];static int __init capi_init(void){ char *p; MOD_INC_USE_COUNT; if ((p = strchr(revision, ':'))) { strcpy(rev, p + 2); p = strchr(rev, '$'); *(p-1) = 0; } else strcpy(rev, "???"); 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; }#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE if (devfs_register_chrdev(capi_rawmajor, "capi/r%d", &capinc_raw_fops)) { devfs_unregister_chrdev(capi_major, "capi20"); printk(KERN_ERR "capi20: unable to get major %d\n", capi_rawmajor); MOD_DEC_USE_COUNT; return -EIO; } devfs_register_series (NULL, "capi/r%u", CAPINC_NR_PORTS, DEVFS_FL_DEFAULT, capi_rawmajor, 0, S_IFCHR | S_IRUSR | S_IWUSR, &capinc_raw_fops, NULL);#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ 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");#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE devfs_unregister_chrdev(capi_rawmajor, "capi/r%d");#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ 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"); devfs_unregister_chrdev(capi_rawmajor, "capi/r%d"); MOD_DEC_USE_COUNT; return -ENOMEM; }#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ if (alloc_init() < 0) {#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE unsigned int j; devfs_unregister_chrdev(capi_rawmajor, "capi/r%d"); for (j = 0; j < CAPINC_NR_PORTS; j++) { char devname[32]; sprintf(devname, "capi/r%u", j); devfs_unregister(devfs_find_handle(NULL, devname, capi_rawmajor, j, DEVFS_SPECIAL_CHR, 0)); } 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(); printk(KERN_NOTICE "capi20: Rev%s: started up with major %d\n", rev, capi_major); MOD_DEC_USE_COUNT; return 0;}static void __exit capi_exit(void){#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE unsigned int j;#endif 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(); devfs_unregister_chrdev(capi_rawmajor, "capi/r%d"); for (j = 0; j < CAPINC_NR_PORTS; j++) { char devname[32]; sprintf(devname, "capi/r%u", j); devfs_unregister(devfs_find_handle(NULL, devname, capi_rawmajor, j, DEVFS_SPECIAL_CHR, 0)); }#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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -