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

📄 sclp_vt220.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (count <= 0)		return 0;	overall_written = 0;	spin_lock_irqsave(&sclp_vt220_lock, flags);	do {		/* Create a sclp output buffer if none exists yet */		if (sclp_vt220_current_request == NULL) {			while (list_empty(&sclp_vt220_empty)) {				spin_unlock_irqrestore(&sclp_vt220_lock,						       flags);				if (in_interrupt())					sclp_sync_wait();				else					wait_event(sclp_vt220_waitq,						!list_empty(&sclp_vt220_empty));				spin_lock_irqsave(&sclp_vt220_lock, flags);			}			page = (void *) sclp_vt220_empty.next;			list_del((struct list_head *) page);			sclp_vt220_current_request =				sclp_vt220_initialize_page(page);		}		/* Try to write the string to the current request buffer */		written = sclp_vt220_add_msg(sclp_vt220_current_request,					     buf, count, convertlf);		overall_written += written;		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.		 */		spin_unlock_irqrestore(&sclp_vt220_lock, flags);		sclp_vt220_emit_current();		spin_lock_irqsave(&sclp_vt220_lock, flags);		buf += written;		count -= written;	} while (count > 0);	/* Setup timer to output current console buffer after some time */	if (sclp_vt220_current_request != NULL &&	    !timer_pending(&sclp_vt220_timer) && do_schedule) {		sclp_vt220_timer.function = sclp_vt220_timeout;		sclp_vt220_timer.data = 0UL;		sclp_vt220_timer.expires = jiffies + BUFFER_MAX_DELAY;		add_timer(&sclp_vt220_timer);	}	spin_unlock_irqrestore(&sclp_vt220_lock, flags);	return overall_written;}/* * 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_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count){	return __sclp_vt220_write(buf, count, 1, 0);}#define SCLP_VT220_SESSION_ENDED	0x01#define	SCLP_VT220_SESSION_STARTED	0x80#define SCLP_VT220_SESSION_DATA		0x00/* * Called by the SCLP to report incoming event buffers. */static voidsclp_vt220_receiver_fn(struct evbuf_header *evbuf){	char *buffer;	unsigned int count;	/* Ignore input if device is not open */	if (sclp_vt220_tty == NULL)		return;	buffer = (char *) ((addr_t) evbuf + sizeof(struct evbuf_header));	count = evbuf->length - sizeof(struct evbuf_header);	switch (*buffer) {	case SCLP_VT220_SESSION_ENDED:	case SCLP_VT220_SESSION_STARTED:		break;	case SCLP_VT220_SESSION_DATA:		/* Send input to line discipline */		buffer++;		count--;		/* Prevent buffer overrun by discarding input. Note that		 * because buffer_push works asynchronously, we cannot wait		 * for the buffer to be emptied. */		if (count + sclp_vt220_tty->flip.count > TTY_FLIPBUF_SIZE)			count = TTY_FLIPBUF_SIZE - sclp_vt220_tty->flip.count;		memcpy(sclp_vt220_tty->flip.char_buf_ptr, buffer, count);		memset(sclp_vt220_tty->flip.flag_buf_ptr, TTY_NORMAL, count);		sclp_vt220_tty->flip.char_buf_ptr += count;		sclp_vt220_tty->flip.flag_buf_ptr += count;		sclp_vt220_tty->flip.count += count;		tty_flip_buffer_push(sclp_vt220_tty);		break;	}}/* * This routine is called when a particular tty device is opened. */static intsclp_vt220_open(struct tty_struct *tty, struct file *filp){	if (tty->count == 1) {		sclp_vt220_tty = tty;		tty->driver_data = kmalloc(SCLP_VT220_BUF_SIZE, GFP_KERNEL);		if (tty->driver_data == NULL)			return -ENOMEM;		tty->low_latency = 0;	}	return 0;}/* * This routine is called when a particular tty device is closed. */static voidsclp_vt220_close(struct tty_struct *tty, struct file *filp){	if (tty->count == 1) {		sclp_vt220_tty = NULL;		kfree(tty->driver_data);		tty->driver_data = NULL;	}}/* * 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. * * NOTE: include/linux/tty_driver.h specifies that a character should be * ignored if there is no room in the queue. This driver implements a different * semantic in that it will block when there is no more room left. */static voidsclp_vt220_put_char(struct tty_struct *tty, unsigned char ch){	__sclp_vt220_write(&ch, 1, 0, 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_vt220_flush_chars(struct tty_struct *tty){	if (sclp_vt220_outqueue_count == 0)		sclp_vt220_emit_current();	else		sclp_vt220_flush_later = 1;}/* * 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. */static intsclp_vt220_write_room(struct tty_struct *tty){	unsigned long flags;	struct list_head *l;	int count;	spin_lock_irqsave(&sclp_vt220_lock, flags);	count = 0;	if (sclp_vt220_current_request != NULL)		count = sclp_vt220_space_left(sclp_vt220_current_request);	list_for_each(l, &sclp_vt220_empty)		count += SCLP_VT220_MAX_CHARS_PER_BUFFER;	spin_unlock_irqrestore(&sclp_vt220_lock, flags);	return count;}/* * Return number of buffered chars. */static intsclp_vt220_chars_in_buffer(struct tty_struct *tty){	unsigned long flags;	struct list_head *l;	struct sclp_vt220_request *r;	int count;	spin_lock_irqsave(&sclp_vt220_lock, flags);	count = 0;	if (sclp_vt220_current_request != NULL)		count = sclp_vt220_chars_stored(sclp_vt220_current_request);	list_for_each(l, &sclp_vt220_outqueue) {		r = list_entry(l, struct sclp_vt220_request, list);		count += sclp_vt220_chars_stored(r);	}	spin_unlock_irqrestore(&sclp_vt220_lock, flags);	return count;}static void__sclp_vt220_flush_buffer(void){	unsigned long flags;	sclp_vt220_emit_current();	spin_lock_irqsave(&sclp_vt220_lock, flags);	if (timer_pending(&sclp_vt220_timer))		del_timer(&sclp_vt220_timer);	while (sclp_vt220_outqueue_count > 0) {		spin_unlock_irqrestore(&sclp_vt220_lock, flags);		sclp_sync_wait();		spin_lock_irqsave(&sclp_vt220_lock, flags);	}	spin_unlock_irqrestore(&sclp_vt220_lock, flags);}/* * Pass on all buffers to the hardware. Return only when there are no more * buffers pending. */static voidsclp_vt220_flush_buffer(struct tty_struct *tty){	sclp_vt220_emit_current();}/* * Initialize all relevant components and register driver with system. */static int__sclp_vt220_init(int early){	void *page;	int i;	if (sclp_vt220_initialized)		return 0;	sclp_vt220_initialized = 1;	spin_lock_init(&sclp_vt220_lock);	INIT_LIST_HEAD(&sclp_vt220_empty);	INIT_LIST_HEAD(&sclp_vt220_outqueue);	init_waitqueue_head(&sclp_vt220_waitq);	init_timer(&sclp_vt220_timer);	sclp_vt220_current_request = NULL;	sclp_vt220_buffered_chars = 0;	sclp_vt220_outqueue_count = 0;	sclp_vt220_tty = NULL;	sclp_vt220_flush_later = 0;	/* Allocate pages for output buffering */	for (i = 0; i < (early ? MAX_CONSOLE_PAGES : MAX_KMEM_PAGES); i++) {		if (early)			page = alloc_bootmem_low_pages(PAGE_SIZE);		else			page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);		if (!page)			return -ENOMEM;		list_add_tail((struct list_head *) page, &sclp_vt220_empty);	}	return 0;}static struct tty_operations sclp_vt220_ops = {	.open = sclp_vt220_open,	.close = sclp_vt220_close,	.write = sclp_vt220_write,	.put_char = sclp_vt220_put_char,	.flush_chars = sclp_vt220_flush_chars,	.write_room = sclp_vt220_write_room,	.chars_in_buffer = sclp_vt220_chars_in_buffer,	.flush_buffer = sclp_vt220_flush_buffer};/* * Register driver with SCLP and Linux and initialize internal tty structures. */int __initsclp_vt220_tty_init(void){	struct tty_driver *driver;	int rc;	/* Note: we're not testing for CONSOLE_IS_SCLP here to preserve	 * symmetry between VM and LPAR systems regarding ttyS1. */	driver = alloc_tty_driver(1);	if (!driver)		return -ENOMEM;	rc = __sclp_vt220_init(0);	if (rc) {		put_tty_driver(driver);		return rc;	}	rc = sclp_register(&sclp_vt220_register);	if (rc) {		printk(KERN_ERR SCLP_VT220_PRINT_HEADER		       "could not register tty - "		       "sclp_register returned %d\n", rc);		put_tty_driver(driver);		return rc;	}	driver->owner = THIS_MODULE;	driver->driver_name = SCLP_VT220_DRIVER_NAME;	driver->name = SCLP_VT220_DEVICE_NAME;	driver->major = SCLP_VT220_MAJOR;	driver->minor_start = SCLP_VT220_MINOR;	driver->type = TTY_DRIVER_TYPE_SYSTEM;	driver->subtype = SYSTEM_TYPE_TTY;	driver->init_termios = tty_std_termios;	driver->flags = TTY_DRIVER_REAL_RAW;	tty_set_operations(driver, &sclp_vt220_ops);	rc = tty_register_driver(driver);	if (rc) {		printk(KERN_ERR SCLP_VT220_PRINT_HEADER		       "could not register tty - "		       "tty_register_driver returned %d\n", rc);		put_tty_driver(driver);		return rc;	}	sclp_vt220_driver = driver;	return 0;}module_init(sclp_vt220_tty_init);#ifdef CONFIG_SCLP_VT220_CONSOLEstatic voidsclp_vt220_con_write(struct console *con, const char *buf, unsigned int count){	__sclp_vt220_write((const unsigned char *) buf, count, 1, 1);}static struct tty_driver *sclp_vt220_con_device(struct console *c, int *index){	*index = 0;	return sclp_vt220_driver;}/* * This routine is called from panic when the kernel is going to give up. * We have to make sure that all buffers will be flushed to the SCLP. * Note that this function may be called from within an interrupt context. */static voidsclp_vt220_con_unblank(void){	__sclp_vt220_flush_buffer();}/* Structure needed to register with printk */static struct console sclp_vt220_console ={	.name = SCLP_VT220_CONSOLE_NAME,	.write = sclp_vt220_con_write,	.device = sclp_vt220_con_device,	.unblank = sclp_vt220_con_unblank,	.flags = CON_PRINTBUFFER,	.index = SCLP_VT220_CONSOLE_INDEX};static int __initsclp_vt220_con_init(void){	int rc;	if (!CONSOLE_IS_SCLP)		return 0;	rc = __sclp_vt220_init(1);	if (rc)		return rc;	/* Attach linux console */	register_console(&sclp_vt220_console);	return 0;}console_initcall(sclp_vt220_con_init);#endif /* CONFIG_SCLP_VT220_CONSOLE */

⌨️ 快捷键说明

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