📄 sclp_vt220.c
字号:
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 + -