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

📄 sclp_tty.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * This routine is called by the kernel to write a single character to the tty * device. If the kernel uses this routine, it must call the flush_chars() * routine (if defined) when it is done stuffing characters into the driver. * * Characters provided to sclp_tty_put_char() are buffered by the SCLP driver. * If the given character is a '\n' the contents of the SCLP write buffer * - including previous characters from sclp_tty_put_char() and strings from * sclp_write() without final '\n' - will be written. */static voidsclp_tty_put_char(struct tty_struct *tty, unsigned char ch){	sclp_tty_chars[sclp_tty_chars_count++] = ch;	if (ch == '\n' || sclp_tty_chars_count >= SCLP_TTY_BUF_SIZE) {		sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);		sclp_tty_chars_count = 0;	}}/* * This routine is called by the kernel after it has written a series of * characters to the tty device using put_char(). */static voidsclp_tty_flush_chars(struct tty_struct *tty){	if (sclp_tty_chars_count > 0) {		sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);		sclp_tty_chars_count = 0;	}}/* * This routine returns the number of characters in the write buffer of the * SCLP driver. The provided number includes all characters that are stored * in the SCCB (will be written next time the SCLP is not busy) as well as * characters in the write buffer (will not be written as long as there is a * final line feed missing). */static intsclp_tty_chars_in_buffer(struct tty_struct *tty){	unsigned long flags;	struct list_head *l;	struct sclp_buffer *t;	int count;	spin_lock_irqsave(&sclp_tty_lock, flags);	count = 0;	if (sclp_ttybuf != NULL)		count = sclp_chars_in_buffer(sclp_ttybuf);	list_for_each(l, &sclp_tty_outqueue) {		t = list_entry(l, struct sclp_buffer, list);		count += sclp_chars_in_buffer(t);	}	spin_unlock_irqrestore(&sclp_tty_lock, flags);	return count;}/* * removes all content from buffers of low level driver */static voidsclp_tty_flush_buffer(struct tty_struct *tty){	if (sclp_tty_chars_count > 0) {		sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);		sclp_tty_chars_count = 0;	}}/* * push input to tty */static voidsclp_tty_input(unsigned char* buf, unsigned int count){	unsigned int cchar;	/*	 * If this tty driver is currently closed	 * then throw the received input away.	 */	if (sclp_tty == NULL)		return;	cchar = ctrlchar_handle(buf, count, sclp_tty);	switch (cchar & CTRLCHAR_MASK) {	case CTRLCHAR_SYSRQ:		break;	case CTRLCHAR_CTRL:		sclp_tty->flip.count++;		*sclp_tty->flip.flag_buf_ptr++ = TTY_NORMAL;		*sclp_tty->flip.char_buf_ptr++ = cchar;		tty_flip_buffer_push(sclp_tty);		break;	case CTRLCHAR_NONE:		/* send (normal) input to line discipline */		memcpy(sclp_tty->flip.char_buf_ptr, buf, count);		if (count < 2 ||		    (strncmp ((const char *) buf + count - 2, "^n", 2) &&		     strncmp ((const char *) buf + count - 2, "\0252n", 2))) {			sclp_tty->flip.char_buf_ptr[count] = '\n';			count++;		} else			count -= 2;		memset(sclp_tty->flip.flag_buf_ptr, TTY_NORMAL, count);		sclp_tty->flip.char_buf_ptr += count;		sclp_tty->flip.flag_buf_ptr += count;		sclp_tty->flip.count += count;		tty_flip_buffer_push(sclp_tty);		break;	}}/* * get a EBCDIC string in upper/lower case, * find out characters in lower/upper case separated by a special character, * modifiy original string, * returns length of resulting string */static intsclp_switch_cases(unsigned char *buf, int count,		  unsigned char delim, int tolower){	unsigned char *ip, *op;	int toggle;	/* initially changing case is off */	toggle = 0;	ip = op = buf;	while (count-- > 0) {		/* compare with special character */		if (*ip == delim) {			/* followed by another special character? */			if (count && ip[1] == delim) {				/*				 * ... then put a single copy of the special				 * character to the output string				 */				*op++ = *ip++;				count--;			} else				/*				 * ... special character follower by a normal				 * character toggles the case change behaviour				 */				toggle = ~toggle;			/* skip special character */			ip++;		} else			/* not the special character */			if (toggle)				/* but case switching is on */				if (tolower)					/* switch to uppercase */					*op++ = _ebc_toupper[(int) *ip++];				else					/* switch to lowercase */					*op++ = _ebc_tolower[(int) *ip++];			else				/* no case switching, copy the character */				*op++ = *ip++;	}	/* return length of reformatted string. */	return op - buf;}static voidsclp_get_input(unsigned char *start, unsigned char *end){	int count;	count = end - start;	/*	 * if set in ioctl convert EBCDIC to lower case	 * (modify original input in SCCB)	 */	if (sclp_ioctls.tolower)		EBC_TOLOWER(start, count);	/*	 * if set in ioctl find out characters in lower or upper case	 * (depends on current case) separated by a special character,	 * works on EBCDIC	 */	if (sclp_ioctls.delim)		count = sclp_switch_cases(start, count,					  sclp_ioctls.delim,					  sclp_ioctls.tolower);	/* convert EBCDIC to ASCII (modify original input in SCCB) */	sclp_ebcasc_str(start, count);	/* if set in ioctl write operators input to console  */	if (sclp_ioctls.echo)		sclp_tty_write(sclp_tty, start, count);	/* transfer input to high level driver */	sclp_tty_input(start, count);}static inline struct gds_vector *find_gds_vector(struct gds_vector *start, struct gds_vector *end, u16 id){	struct gds_vector *vec;	for (vec = start; vec < end; vec = (void *) vec + vec->length)		if (vec->gds_id == id)			return vec;	return NULL;}static inline struct gds_subvector *find_gds_subvector(struct gds_subvector *start,		   struct gds_subvector *end, u8 key){	struct gds_subvector *subvec;	for (subvec = start; subvec < end;	     subvec = (void *) subvec + subvec->length)		if (subvec->key == key)			return subvec;	return NULL;}static inline voidsclp_eval_selfdeftextmsg(struct gds_subvector *start,			 struct gds_subvector *end){	struct gds_subvector *subvec;	subvec = start;	while (subvec < end) {		subvec = find_gds_subvector(subvec, end, 0x30);		if (!subvec)			break;		sclp_get_input((unsigned char *)(subvec + 1),			       (unsigned char *) subvec + subvec->length);		subvec = (void *) subvec + subvec->length;	}}static inline voidsclp_eval_textcmd(struct gds_subvector *start,		  struct gds_subvector *end){	struct gds_subvector *subvec;	subvec = start;	while (subvec < end) {		subvec = find_gds_subvector(subvec, end,					    GDS_KEY_SelfDefTextMsg);		if (!subvec)			break;		sclp_eval_selfdeftextmsg((struct gds_subvector *)(subvec + 1),					 (void *)subvec + subvec->length);		subvec = (void *) subvec + subvec->length;	}}static inline voidsclp_eval_cpmsu(struct gds_vector *start, struct gds_vector *end){	struct gds_vector *vec;	vec = start;	while (vec < end) {		vec = find_gds_vector(vec, end, GDS_ID_TextCmd);		if (!vec)			break;		sclp_eval_textcmd((struct gds_subvector *)(vec + 1),				  (void *) vec + vec->length);		vec = (void *) vec + vec->length;	}}static inline voidsclp_eval_mdsmu(struct gds_vector *start, void *end){	struct gds_vector *vec;	vec = find_gds_vector(start, end, GDS_ID_CPMSU);	if (vec)		sclp_eval_cpmsu(vec + 1, (void *) vec + vec->length);}static voidsclp_tty_receiver(struct evbuf_header *evbuf){	struct gds_vector *start, *end, *vec;	start = (struct gds_vector *)(evbuf + 1);	end = (void *) evbuf + evbuf->length;	vec = find_gds_vector(start, end, GDS_ID_MDSMU);	if (vec)		sclp_eval_mdsmu(vec + 1, (void *) vec + vec->length);}static voidsclp_tty_state_change(struct sclp_register *reg){}static struct sclp_register sclp_input_event ={	.receive_mask = EvTyp_OpCmd_Mask | EvTyp_PMsgCmd_Mask,	.state_change_fn = sclp_tty_state_change,	.receiver_fn = sclp_tty_receiver};static struct tty_operations sclp_ops = {	.open = sclp_tty_open,	.close = sclp_tty_close,	.write = sclp_tty_write,	.put_char = sclp_tty_put_char,	.flush_chars = sclp_tty_flush_chars,	.write_room = sclp_tty_write_room,	.chars_in_buffer = sclp_tty_chars_in_buffer,	.flush_buffer = sclp_tty_flush_buffer,	.ioctl = sclp_tty_ioctl,};int __initsclp_tty_init(void){	struct tty_driver *driver;	void *page;	int i;	int rc;	if (!CONSOLE_IS_SCLP)		return 0;	driver = alloc_tty_driver(1);	if (!driver)		return -ENOMEM;	rc = sclp_rw_init();	if (rc) {		printk(KERN_ERR SCLP_TTY_PRINT_HEADER		       "could not register tty - "		       "sclp_rw_init returned %d\n", rc);		put_tty_driver(driver);		return rc;	}	/* Allocate pages for output buffering */	INIT_LIST_HEAD(&sclp_tty_pages);	for (i = 0; i < MAX_KMEM_PAGES; i++) {		page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);		if (page == NULL) {			put_tty_driver(driver);			return -ENOMEM;		}		list_add_tail((struct list_head *) page, &sclp_tty_pages);	}	INIT_LIST_HEAD(&sclp_tty_outqueue);	spin_lock_init(&sclp_tty_lock);	init_waitqueue_head(&sclp_tty_waitq);	init_timer(&sclp_tty_timer);	sclp_ttybuf = NULL;	sclp_tty_buffer_count = 0;	if (MACHINE_IS_VM) {		/*		 * save 4 characters for the CPU number		 * written at start of each line by VM/CP		 */		sclp_ioctls_init.columns = 76;		/* case input lines to lowercase */		sclp_ioctls_init.tolower = 1;	}	sclp_ioctls = sclp_ioctls_init;	sclp_tty_chars_count = 0;	sclp_tty = NULL;	rc = sclp_register(&sclp_input_event);	if (rc) {		put_tty_driver(driver);		return rc;	}	driver->owner = THIS_MODULE;	driver->driver_name = "sclp_line";	driver->name = "sclp_line";	driver->major = TTY_MAJOR;	driver->minor_start = 64;	driver->type = TTY_DRIVER_TYPE_SYSTEM;	driver->subtype = SYSTEM_TYPE_TTY;	driver->init_termios = tty_std_termios;	driver->init_termios.c_iflag = IGNBRK | IGNPAR;	driver->init_termios.c_oflag = ONLCR | XTABS;	driver->init_termios.c_lflag = ISIG | ECHO;	driver->flags = TTY_DRIVER_REAL_RAW;	tty_set_operations(driver, &sclp_ops);	rc = tty_register_driver(driver);	if (rc) {		printk(KERN_ERR SCLP_TTY_PRINT_HEADER		       "could not register tty - "		       "tty_register_driver returned %d\n", rc);		put_tty_driver(driver);		return rc;	}	sclp_tty_driver = driver;	return 0;}module_init(sclp_tty_init);

⌨️ 快捷键说明

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