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 + -
显示快捷键?