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

📄 sclp_tty.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  drivers/s390/char/sclp_tty.c *    SCLP line mode terminal driver. * *  S390 version *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation *    Author(s): Martin Peschke <mpeschke@de.ibm.com> *		 Martin Schwidefsky <schwidefsky@de.ibm.com> */#include <linux/config.h>#include <linux/module.h>#include <linux/kmod.h>#include <linux/tty.h>#include <linux/tty_driver.h>#include <linux/sched.h>#include <linux/wait.h>#include <linux/slab.h>#include <linux/err.h>#include <linux/init.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include "ctrlchar.h"#include "sclp.h"#include "sclp_rw.h"#include "sclp_tty.h"#define SCLP_TTY_PRINT_HEADER "sclp tty driver: "/* * size of a buffer that collects single characters coming in * via sclp_tty_put_char() */#define SCLP_TTY_BUF_SIZE 512/* * There is exactly one SCLP terminal, so we can keep things simple * and allocate all variables statically. *//* Lock to guard over changes to global variables. */static spinlock_t sclp_tty_lock;/* List of free pages that can be used for console output buffering. */static struct list_head sclp_tty_pages;/* List of full struct sclp_buffer structures ready for output. */static struct list_head sclp_tty_outqueue;/* Counter how many buffers are emitted. */static int sclp_tty_buffer_count;/* Pointer to current console buffer. */static struct sclp_buffer *sclp_ttybuf;/* Timer for delayed output of console messages. */static struct timer_list sclp_tty_timer;/* Waitqueue to wait for buffers to get empty. */static wait_queue_head_t sclp_tty_waitq;static struct tty_struct *sclp_tty;static unsigned char sclp_tty_chars[SCLP_TTY_BUF_SIZE];static unsigned short int sclp_tty_chars_count;struct tty_driver *sclp_tty_driver;extern struct termios  tty_std_termios;static struct sclp_ioctls sclp_ioctls;static struct sclp_ioctls sclp_ioctls_init ={	8,			/* 1 hor. tab. = 8 spaces */	0,			/* no echo of input by this driver */	80,			/* 80 characters/line */	1,			/* write after 1/10 s without final new line */	MAX_KMEM_PAGES,		/* quick fix: avoid __alloc_pages */	MAX_KMEM_PAGES,		/* take 32/64 pages from kernel memory, */	0,			/* do not convert to lower case */	0x6c			/* to seprate upper and lower case */				/* ('%' in EBCDIC) */};/* This routine is called whenever we try to open a SCLP terminal. */static intsclp_tty_open(struct tty_struct *tty, struct file *filp){	sclp_tty = tty;	tty->driver_data = NULL;	tty->low_latency = 0;	return 0;}/* This routine is called when the SCLP terminal is closed. */static voidsclp_tty_close(struct tty_struct *tty, struct file *filp){	if (tty->count > 1)		return;	sclp_tty = NULL;}/* execute commands to control the i/o behaviour of the SCLP tty at runtime */static intsclp_tty_ioctl(struct tty_struct *tty, struct file * file,	       unsigned int cmd, unsigned long arg){	unsigned long flags;	unsigned int obuf;	int check;	int rc;	if (tty->flags & (1 << TTY_IO_ERROR))		return -EIO;	rc = 0;	check = 0;	switch (cmd) {	case TIOCSCLPSHTAB:		/* set width of horizontal tab	*/		if (get_user(sclp_ioctls.htab, (unsigned short __user *) arg))			rc = -EFAULT;		else			check = 1;		break;	case TIOCSCLPGHTAB:		/* get width of horizontal tab	*/		if (put_user(sclp_ioctls.htab, (unsigned short __user *) arg))			rc = -EFAULT;		break;	case TIOCSCLPSECHO:		/* enable/disable echo of input */		if (get_user(sclp_ioctls.echo, (unsigned char __user *) arg))			rc = -EFAULT;		break;	case TIOCSCLPGECHO:		/* Is echo of input enabled ?  */		if (put_user(sclp_ioctls.echo, (unsigned char __user *) arg))			rc = -EFAULT;		break;	case TIOCSCLPSCOLS:		/* set number of columns for output  */		if (get_user(sclp_ioctls.columns, (unsigned short __user *) arg))			rc = -EFAULT;		else			check = 1;		break;	case TIOCSCLPGCOLS:		/* get number of columns for output  */		if (put_user(sclp_ioctls.columns, (unsigned short __user *) arg))			rc = -EFAULT;		break;	case TIOCSCLPSNL:		/* enable/disable writing without final new line character  */		if (get_user(sclp_ioctls.final_nl, (signed char __user *) arg))			rc = -EFAULT;		break;	case TIOCSCLPGNL:		/* Is writing without final new line character enabled ?  */		if (put_user(sclp_ioctls.final_nl, (signed char __user *) arg))			rc = -EFAULT;		break;	case TIOCSCLPSOBUF:		/*		 * set the maximum buffers size for output, will be rounded		 * up to next 4kB boundary and stored as number of SCCBs		 * (4kB Buffers) limitation: 256 x 4kB		 */		if (get_user(obuf, (unsigned int __user *) arg) == 0) {			if (obuf & 0xFFF)				sclp_ioctls.max_sccb = (obuf >> 12) + 1;			else				sclp_ioctls.max_sccb = (obuf >> 12);		} else			rc = -EFAULT;		break;	case TIOCSCLPGOBUF:		/* get the maximum buffers size for output  */		obuf = sclp_ioctls.max_sccb << 12;		if (put_user(obuf, (unsigned int __user *) arg))			rc = -EFAULT;		break;	case TIOCSCLPGKBUF:		/* get the number of buffers got from kernel at startup */		if (put_user(sclp_ioctls.kmem_sccb, (unsigned short __user *) arg))			rc = -EFAULT;		break;	case TIOCSCLPSCASE:		/* enable/disable conversion from upper to lower case */		if (get_user(sclp_ioctls.tolower, (unsigned char __user *) arg))			rc = -EFAULT;		break;	case TIOCSCLPGCASE:		/* Is conversion from upper to lower case of input enabled? */		if (put_user(sclp_ioctls.tolower, (unsigned char __user *) arg))			rc = -EFAULT;		break;	case TIOCSCLPSDELIM:		/*		 * set special character used for separating upper and		 * lower case, 0x00 disables this feature		 */		if (get_user(sclp_ioctls.delim, (unsigned char __user *) arg))			rc = -EFAULT;		break;	case TIOCSCLPGDELIM:		/*		 * get special character used for separating upper and		 * lower case, 0x00 disables this feature		 */		if (put_user(sclp_ioctls.delim, (unsigned char __user *) arg))			rc = -EFAULT;		break;	case TIOCSCLPSINIT:		/* set initial (default) sclp ioctls  */		sclp_ioctls = sclp_ioctls_init;		check = 1;		break;	default:		rc = -ENOIOCTLCMD;		break;	}	if (check) {		spin_lock_irqsave(&sclp_tty_lock, flags);		if (sclp_ttybuf != NULL) {			sclp_set_htab(sclp_ttybuf, sclp_ioctls.htab);			sclp_set_columns(sclp_ttybuf, sclp_ioctls.columns);		}		spin_unlock_irqrestore(&sclp_tty_lock, flags);	}	return rc;}/* * This routine returns the numbers of characters the tty driver * will accept for queuing to be written.  This number is subject * to change as output buffers get emptied, or if the output flow * control is acted. This is not an exact number because not every * character needs the same space in the sccb. The worst case is * a string of newlines. Every newlines creates a new mto which * needs 8 bytes. */static intsclp_tty_write_room (struct tty_struct *tty){	unsigned long flags;	struct list_head *l;	int count;	spin_lock_irqsave(&sclp_tty_lock, flags);	count = 0;	if (sclp_ttybuf != NULL)		count = sclp_buffer_space(sclp_ttybuf) / sizeof(struct mto);	list_for_each(l, &sclp_tty_pages)		count += NR_EMPTY_MTO_PER_SCCB;	spin_unlock_irqrestore(&sclp_tty_lock, flags);	return count;}static voidsclp_ttybuf_callback(struct sclp_buffer *buffer, int rc){	unsigned long flags;	void *page;	do {		page = sclp_unmake_buffer(buffer);		spin_lock_irqsave(&sclp_tty_lock, flags);		/* Remove buffer from outqueue */		list_del(&buffer->list);		sclp_tty_buffer_count--;		list_add_tail((struct list_head *) page, &sclp_tty_pages);		/* Check if there is a pending buffer on the out queue. */		buffer = NULL;		if (!list_empty(&sclp_tty_outqueue))			buffer = list_entry(sclp_tty_outqueue.next,					    struct sclp_buffer, list);		spin_unlock_irqrestore(&sclp_tty_lock, flags);	} while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback));	wake_up(&sclp_tty_waitq);	/* check if the tty needs a wake up call */	if (sclp_tty != NULL) {		tty_wakeup(sclp_tty);	}}static inline void__sclp_ttybuf_emit(struct sclp_buffer *buffer){	unsigned long flags;	int count;	int rc;	spin_lock_irqsave(&sclp_tty_lock, flags);	list_add_tail(&buffer->list, &sclp_tty_outqueue);	count = sclp_tty_buffer_count++;	spin_unlock_irqrestore(&sclp_tty_lock, flags);	if (count)		return;	rc = sclp_emit_buffer(buffer, sclp_ttybuf_callback);	if (rc)		sclp_ttybuf_callback(buffer, rc);}/* * When this routine is called from the timer then we flush the * temporary write buffer. */static voidsclp_tty_timeout(unsigned long data){	unsigned long flags;	struct sclp_buffer *buf;	spin_lock_irqsave(&sclp_tty_lock, flags);	buf = sclp_ttybuf;	sclp_ttybuf = NULL;	spin_unlock_irqrestore(&sclp_tty_lock, flags);	if (buf != NULL) {		__sclp_ttybuf_emit(buf);	}}/* * Write a string to the sclp tty. */static voidsclp_tty_write_string(const unsigned char *str, int count){	unsigned long flags;	void *page;	int written;	struct sclp_buffer *buf;	if (count <= 0)		return;	spin_lock_irqsave(&sclp_tty_lock, flags);	do {		/* Create a sclp output buffer if none exists yet */		if (sclp_ttybuf == NULL) {			while (list_empty(&sclp_tty_pages)) {				spin_unlock_irqrestore(&sclp_tty_lock, flags);				if (in_interrupt())					sclp_sync_wait();				else					wait_event(sclp_tty_waitq,						!list_empty(&sclp_tty_pages));				spin_lock_irqsave(&sclp_tty_lock, flags);			}			page = sclp_tty_pages.next;			list_del((struct list_head *) page);			sclp_ttybuf = sclp_make_buffer(page,						       sclp_ioctls.columns,						       sclp_ioctls.htab);		}		/* try to write the string to the current output buffer */		written = sclp_write(sclp_ttybuf, str, count);		if (written == count)			break;		/*		 * Not all characters could be written to the current		 * output buffer. Emit the buffer, create a new buffer		 * and then output the rest of the string.		 */		buf = sclp_ttybuf;		sclp_ttybuf = NULL;		spin_unlock_irqrestore(&sclp_tty_lock, flags);		__sclp_ttybuf_emit(buf);		spin_lock_irqsave(&sclp_tty_lock, flags);		str += written;		count -= written;	} while (count > 0);	/* Setup timer to output current console buffer after 1/10 second */	if (sclp_ioctls.final_nl) {		if (sclp_ttybuf != NULL &&		    sclp_chars_in_buffer(sclp_ttybuf) != 0 &&		    !timer_pending(&sclp_tty_timer)) {			init_timer(&sclp_tty_timer);			sclp_tty_timer.function = sclp_tty_timeout;			sclp_tty_timer.data = 0UL;			sclp_tty_timer.expires = jiffies + HZ/10;			add_timer(&sclp_tty_timer);		}	} else {		if (sclp_ttybuf != NULL &&		    sclp_chars_in_buffer(sclp_ttybuf) != 0) {			buf = sclp_ttybuf;			sclp_ttybuf = NULL;			spin_unlock_irqrestore(&sclp_tty_lock, flags);			__sclp_ttybuf_emit(buf);			spin_lock_irqsave(&sclp_tty_lock, flags);		}	}	spin_unlock_irqrestore(&sclp_tty_lock, flags);}/* * This routine is called by the kernel to write a series of characters to the * tty device. The characters may come from user space or kernel space. This * routine will return the number of characters actually accepted for writing. */static intsclp_tty_write(struct tty_struct *tty, const unsigned char *buf, int count){	if (sclp_tty_chars_count > 0) {		sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);		sclp_tty_chars_count = 0;	}	sclp_tty_write_string(buf, count);	return count;}

⌨️ 快捷键说明

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