⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tuball.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
字号:
/* *  IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC * *  tuball.c -- Initialization, termination, irq lookup * * * * * *  Author:  Richard Hitt */#include <linux/config.h>#include "tubio.h"#ifndef MODULE#include <linux/init.h>#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))#include <asm/cpcmd.h>#include <linux/bootmem.h>#else#include "../../../../arch/s390/kernel/cpcmd.h"#endif#endif/* Module parameters */int tubdebug;int tubscrolltime = -1;int tubxcorrect = 1;            /* Do correct ebc<->asc tables */#ifdef MODULEMODULE_PARM(tubdebug, "i");MODULE_PARM(tubscrolltime, "i");MODULE_PARM(tubxcorrect, "i");#endif/* * Values for tubdebug and their effects: * 1 - print in hex on console the first 16 bytes received * 2 - print address at which array tubminors is allocated * 4 - attempt to register tty3270_driver */int tubnummins;tub_t *(*tubminors)[TUBMAXMINS];tub_t *(*(*tubirqs)[256])[256];unsigned char tub_ascebc[256];unsigned char tub_ebcasc[256];int tubinitminors(void);void tubfiniminors(void);void tubint(int, void *, struct pt_regs *);/* Lookup-by-irq functions */int tubaddbyirq(tub_t *, int);tub_t *tubfindbyirq(int);void tubdelbyirq(tub_t *, int);void tubfiniirqs(void);extern int fs3270_init(void);extern void fs3270_fini(void);extern int tty3270_init(void);extern void tty3270_fini(void);unsigned char tub_ebcgraf[64] =	{ 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,	  0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,	  0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,	  0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,	  0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,	  0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,	  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,	  0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f };int tub3270_init(void);#ifndef MODULE/* * Can't have this driver a module & support console at the same time */#ifdef CONFIG_TN3270_CONSOLEstatic kdev_t tub3270_con_device(struct console *);static void tub3270_con_unblank(void);static void tub3270_con_write(struct console *, const char *,	unsigned int);static struct console tub3270_con = {	"tub3270",		/* name */	tub3270_con_write,	/* write */	NULL,			/* read */	tub3270_con_device,	/* device */	NULL,			/* wait_key */	tub3270_con_unblank,	/* unblank */	NULL,			/* setup */	CON_PRINTBUFFER,	/* flags */	0,			/* index */	0,			/* cflag */	NULL			/* next */};static bcb_t tub3270_con_bcb;		/* Buffer that receives con writes */static spinlock_t tub3270_con_bcblock;	/* Lock for the buffer */int tub3270_con_irq = -1;		/* set nonneg by _activate() */tub_t *tub3270_con_tubp;		/* set nonzero by _activate() */struct tty_driver tty3270_con_driver;	/* for /dev/console at 4, 64 */#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))int tub3270_con_devno = -1;		/* set by tub3270_con_setup() */__initfunc(void tub3270_con_setup(char *str, int *ints)){	int vdev;	vdev = simple_strtoul(str, 0, 16);	if (vdev >= 0 && vdev < 65536)		tub3270_con_devno = vdev;	return;}__initfunc (long tub3270_con_init(long kmem_start, long kmem_end)){	tub3270_con_bcb.bc_len = 65536;	if (!MACHINE_IS_VM && !MACHINE_IS_P390)		return kmem_start;	tub3270_con_bcb.bc_buf = (void *)kmem_start;	kmem_start += tub3270_con_bcb.bc_len;	register_console(&tub3270_con);	return kmem_start;}#else#define tub3270_con_devno console_devicevoid __init tub3270_con_init(void){	tub3270_con_bcb.bc_len = 65536;	if (!CONSOLE_IS_3270)		return;	tub3270_con_bcb.bc_buf = (void *)alloc_bootmem_low(		tub3270_con_bcb.bc_len);	register_console(&tub3270_con);}#endifstatic kdev_ttub3270_con_device(struct console *conp){	return MKDEV(IBM_TTY3270_MAJOR, conp->index + 1);}static voidtub3270_con_unblank(void){	/* flush everything:  panic has occurred */}int tub3270_con_write_deadlock_ct;int tub3270_con_write_deadlock_bytes;static voidtub3270_con_write(struct console *conp,	const char *buf, unsigned int count){	long flags;	tub_t *tubp = tub3270_con_tubp;	void tty3270_sched_bh(tub_t *);	int rc;	bcb_t obcb;	obcb.bc_buf = (char *)buf;	obcb.bc_len = obcb.bc_cnt = obcb.bc_wr =		MIN(count, tub3270_con_bcb.bc_len);	obcb.bc_rd = 0;	spin_lock_irqsave(&tub3270_con_bcblock, flags);	rc = tub3270_movedata(&obcb, &tub3270_con_bcb, 0);	spin_unlock_irqrestore(&tub3270_con_bcblock, flags);	if (tubp && rc && TUBTRYLOCK(tubp->irq, flags)) {		tty3270_sched_bh(tubp);		TUBUNLOCK(tubp->irq, flags);	}}	int tub3270_con_copy(tub_t *tubp){	long flags;	int rc;	spin_lock_irqsave(&tub3270_con_bcblock, flags);	rc = tub3270_movedata(&tub3270_con_bcb, &tubp->tty_bcb, 0);	spin_unlock_irqrestore(&tub3270_con_bcblock, flags);	return rc;}#endif /* CONFIG_TN3270_CONSOLE */#else /* If generated as a MODULE *//* * module init:  find tubes; get a major nbr */intinit_module(void){	if (tubnummins != 0) {		printk(KERN_ERR "EEEK!!  Tube driver cobbigling!!\n");		return -1;	}	return tub3270_init();}/* * remove driver:  unregister the major number */voidcleanup_module(void){	fs3270_fini();	tty3270_fini();	tubfiniminors();}#endif /* Not a MODULE or a MODULE */voidtub_inc_use_count(void){	MOD_INC_USE_COUNT;}voidtub_dec_use_count(void){	MOD_DEC_USE_COUNT;}/* * tub3270_init() called by kernel or module initialization */inttub3270_init(void){	s390_dev_info_t d;	int i, rc;	/*	 * Copy and correct ebcdic - ascii translate tables	 */	memcpy(tub_ascebc, _ascebc, sizeof tub_ascebc);	memcpy(tub_ebcasc, _ebcasc, sizeof tub_ebcasc);	if (tubxcorrect) {		/* correct brackets and circumflex */		tub_ascebc['['] = 0xad;		tub_ascebc[']'] = 0xbd;		tub_ebcasc[0xad] = '[';		tub_ebcasc[0xbd] = ']';		tub_ascebc['^'] = 0xb0;		tub_ebcasc[0x5f] = '^';	}	rc = tubinitminors();	if (rc != 0)		return rc;	if (fs3270_init() || tty3270_init()) {		printk(KERN_ERR "fs3270_init() or tty3270_init() failed\n");		fs3270_fini();		tty3270_fini();		tubfiniminors();		return -1;	}	for (i = get_irq_first(); i >= 0; i = get_irq_next(i)) {		if ((rc = get_dev_info_by_irq(i, &d)))			continue;		if (d.status)			continue;#ifdef CONFIG_TN3270_CONSOLE#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))		if (d.sid_data.cu_type == 0x3215 && MACHINE_IS_VM) {			cpcmd("TERM CONMODE 3270", NULL, 0);			d.sid_data.cu_type = 0x3270;		}#else		if (d.sid_data.cu_type == 0x3215 && CONSOLE_IS_3270) {			cpcmd("TERM CONMODE 3270", NULL, 0);			d.sid_data.cu_type = 0x3270;		}#endif /* LINUX_VERSION_CODE */#endif /* CONFIG_TN3270_CONSOLE */		if ((d.sid_data.cu_type & 0xfff0) != 0x3270)			continue;		rc = tubmakemin(i, &d);		if (rc < 0) {			printk(KERN_WARNING 			       "3270 tube registration ran out of memory"			       " after %d devices\n", tubnummins - 1);			break;		} else {			printk(KERN_INFO "3270: %.4x on sch %d, minor %d\n",				d.devno, d.irq, rc);		}	}	return 0;}/* * tub3270_movedata(bcb_t *, bcb_t *) -- Move data stream */inttub3270_movedata(bcb_t *ib, bcb_t *ob, int fromuser){	int count;			/* Total move length */	int rc;	rc = count = MIN(ib->bc_cnt, ob->bc_len - ob->bc_cnt);	while (count > 0) {		int len1;		/* Contig bytes avail in ib */		if (ib->bc_wr > ib->bc_rd)			len1 = ib->bc_wr - ib->bc_rd;		else			len1 = ib->bc_len - ib->bc_rd;		if (len1 > count)			len1 = count;		while (len1 > 0) {			int len2;	/* Contig space avail in ob */			if (ob->bc_rd > ob->bc_wr)				len2 = ob->bc_rd - ob->bc_wr;			else				len2 = ob->bc_len - ob->bc_wr;			if (len2 > len1)				len2 = len1;						if (fromuser) {				len2 -= copy_from_user(ob->bc_buf + ob->bc_wr,						       ib->bc_buf + ib->bc_rd,						       len2);				if (len2 == 0) {					if (!rc)						rc = -EFAULT;					break;				}			} else				memcpy(ob->bc_buf + ob->bc_wr,				       ib->bc_buf + ib->bc_rd,				       len2);						ib->bc_rd += len2;			if (ib->bc_rd == ib->bc_len)				ib->bc_rd = 0;			ib->bc_cnt -= len2;			ob->bc_wr += len2;			if (ob->bc_wr == ob->bc_len)				ob->bc_wr = 0;			ob->bc_cnt += len2;			len1 -= len2;			count -= len2;		}	}	return rc;}/* * receive an interrupt */voidtubint(int irq, void *ipp, struct pt_regs *prp){	devstat_t *dsp = ipp;	tub_t *tubp;	if ((tubp = IRQ2TUB(irq)) && (tubp->intv))		(tubp->intv)(tubp, dsp);}/* * Initialize array of pointers to minor structures tub_t. * Returns 0 or -ENOMEM. */inttubinitminors(void){	tubminors = (tub_t *(*)[TUBMAXMINS])kmalloc(sizeof *tubminors,		GFP_KERNEL);	if (tubminors == NULL)		return -ENOMEM;	memset(tubminors, 0, sizeof *tubminors);	return 0;}/* * Add a minor 327x device.  Argument is an irq value. * * Point elements of two arrays to the newly created tub_t: * 1. (*tubminors)[minor] * 2. (*(*tubirqs)[irqhi])[irqlo] * The first looks up from minor number at context time; the second * looks up from irq at interrupt time. */int#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))tubmakemin(int irq, dev_info_t *dp)#elsetubmakemin(int irq, s390_dev_info_t *dp)#endif{	tub_t *tubp;	int minor;	long flags;	if ((minor = ++tubnummins) == TUBMAXMINS)		return -ENODEV;	tubp = kmalloc(sizeof(tub_t), GFP_KERNEL);	if (tubp == NULL) {		return -ENOMEM;	}	if (tubaddbyirq(tubp, irq) != 0) {		kfree(tubp);		return -ENOMEM;	}	memset(tubp, 0, sizeof(tub_t));	tubp->minor = minor;	tubp->irq = irq;	TUBLOCK(tubp->irq, flags);	tubp->devno = dp->devno;	tubp->geom_rows = _GEOM_ROWS;	tubp->geom_cols = _GEOM_COLS;	init_waitqueue_head(&tubp->waitq);	tubp->tty_bcb.bc_len = TTY_OUTPUT_SIZE;	tubp->tty_bcb.bc_buf = (void *)kmalloc(tubp->tty_bcb.bc_len,		GFP_KERNEL|GFP_DMA);	if (tubp->tty_bcb.bc_buf == NULL) {		TUBUNLOCK(tubp->irq, flags);		tubdelbyirq(tubp, irq);		kfree(tubp);		return -ENOMEM;	}	tubp->tty_bcb.bc_cnt = 0;	tubp->tty_bcb.bc_wr = 0;	tubp->tty_bcb.bc_rd = 0;	(*tubminors)[minor] = tubp;#ifdef CONFIG_TN3270_CONSOLE	if (CONSOLE_IS_3270) {		if (tub3270_con_tubp == NULL && 		    tub3270_con_bcb.bc_buf != NULL &&		    (tub3270_con_devno == -1 ||		     tub3270_con_devno == dp->devno)) {			extern void tty3270_int(tub_t *, devstat_t *);						tub3270_con_devno = dp->devno;			tubp->cmd = TBC_CONOPEN;			tubp->flags |= TUB_OPEN_STET | TUB_INPUT_HACK;			tty3270_size(tubp, &flags);			tty3270_aid_init(tubp);			tty3270_scl_init(tubp);			tub3270_con_irq = tubp->irq;			tub3270_con_tubp = tubp;			tubp->intv = tty3270_int;			tubp->cmd = TBC_UPDSTAT;			tty3270_build(tubp);		}	}#endif /* CONFIG_TN3270_CONSOLE */#ifdef CONFIG_DEVFS_FS	fs3270_devfs_register(tubp);#endif	TUBUNLOCK(tubp->irq, flags);	return minor;}/* * Release array of pointers to minor structures tub_t, but first * release any storage pointed to by them. */voidtubfiniminors(void){	int i;	tub_t **tubpp, *tubp;	if (tubminors == NULL)		return;	for (i = 0; i < TUBMAXMINS; i++) {		tubpp = &(*tubminors)[i];		if ((tubp = *tubpp)) {#ifdef CONFIG_DEVFS_FS			fs3270_devfs_unregister(tubp);#endif			tubdelbyirq(tubp, tubp->irq);			tty3270_rcl_fini(tubp);			kfree(tubp->tty_bcb.bc_buf);			tubp->tty_bcb.bc_buf = NULL;			tubp->ttyscreen = NULL;			kfree(tubp);			*tubpp = NULL;		}	}	kfree(tubminors);	tubminors = NULL;	tubfiniirqs();}/* * tubaddbyirq() -- Add tub_t for irq lookup in tubint() */inttubaddbyirq(tub_t *tubp, int irq){	int irqhi = (irq >> 8) & 255;	int irqlo = irq & 255;	tub_t *(*itubpp)[256];	/* Allocate array (*tubirqs)[] if first time */	if (tubirqs == NULL) {		tubirqs = (tub_t *(*(*)[256])[256])			kmalloc(sizeof *tubirqs, GFP_KERNEL);		if (tubirqs == NULL)			return -ENOMEM;		memset(tubirqs, 0, sizeof *tubirqs);	}	/* Allocate subarray (*(*tubirqs)[])[] if first use */	if ((itubpp = (*tubirqs)[irqhi]) == NULL) {		itubpp = (tub_t *(*)[256])			kmalloc(sizeof(*itubpp), GFP_KERNEL);		if (itubpp == NULL) {			if (tubnummins == 1) {  /* if first time */				kfree(tubirqs);				tubirqs = NULL;			}			return -ENOMEM;		} else {			memset(itubpp, 0, sizeof(*itubpp));			(*tubirqs)[irqhi] = itubpp;		}	}	/* Request interrupt service */	if ((tubp->irqrc = request_irq(irq, tubint, SA_INTERRUPT,	    "3270 tube driver", &tubp->devstat)) != 0)		return tubp->irqrc;	/* Fill in the proper subarray element */	(*itubpp)[irqlo] = tubp;	return 0;}/* * tubfindbyirq(irq) */tub_t *tubfindbyirq(int irq){	int irqhi = (irq >> 8) & 255;	int irqlo = irq & 255;	tub_t *tubp;	if (tubirqs == NULL)		return NULL;	if ((*tubirqs)[irqhi] == NULL)		return NULL;	tubp = (*(*tubirqs)[irqhi])[irqlo];	if (tubp->irq == irq)		return tubp;	return NULL;}/* * tubdelbyirq(tub_t*, irq) */voidtubdelbyirq(tub_t *tubp, int irq){	int irqhi = (irq >> 8) & 255;	int irqlo = irq & 255;	tub_t *(*itubpp)[256], *itubp;	if (tubirqs == NULL) {		printk(KERN_ERR "tubirqs is NULL\n");		return;	}	itubpp = (*tubirqs)[irqhi];	if (itubpp == NULL) {		printk(KERN_ERR "tubirqs[%d] is NULL\n", irqhi);		return;	}	itubp = (*itubpp)[irqlo];	if (itubp == NULL) {		printk(KERN_ERR "tubirqs[%d][%d] is NULL\n", irqhi, irqlo);		return;	}	if (itubp->irqrc == 0)		free_irq(irq, &itubp->devstat);	(*itubpp)[irqlo] = NULL;}/* * tubfiniirqs() -- clean up storage in tub_t *(*(*tubirqs)[256])[256] */voidtubfiniirqs(void){	int i;	tub_t *(*itubpp)[256];	if (tubirqs != NULL) {		for (i = 0; i < 256; i++) {			if ((itubpp = (*tubirqs)[i])) {				kfree(itubpp);				(*tubirqs)[i] = NULL;			}		}		kfree(tubirqs);		tubirqs = NULL;	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -