viocons.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,334 行 · 第 1/3 页
C
1,334 行
if (event->xFlags.xFunction == HvLpEvent_Function_Ack) { if (port >= VTTY_PORTS) return; spin_lock_irqsave(&consolelock, flags); /* Got the lock, don't cause console output */ pi = &port_info[port]; if (event->xRc == HvLpEvent_Rc_Good) { pi->seq = pi->ack = 0; /* * This line allows connections from the primary * partition but once one is connected from the * primary partition nothing short of a reboot * of linux will allow access from the hosting * partition again without a required iSeries fix. */ pi->lp = event->xTargetLp; } spin_unlock_irqrestore(&consolelock, flags); if (event->xRc != HvLpEvent_Rc_Good) printk(VIOCONS_KERN_WARN "handle_open_event: event->xRc == (%d).\n", event->xRc); if (event->xCorrelationToken != 0) { atomic_t *aptr= (atomic_t *)event->xCorrelationToken; atomic_set(aptr, 1); } else printk(VIOCONS_KERN_WARN "wierd...got open ack without atomic\n"); return; } /* This had better require an ack, otherwise complain */ if (event->xFlags.xAckInd != HvLpEvent_AckInd_DoAck) { printk(VIOCONS_KERN_WARN "viocharopen without ack bit!\n"); return; } spin_lock_irqsave(&consolelock, flags); /* Got the lock, don't cause console output */ /* Make sure this is a good virtual tty */ if (port >= VTTY_PORTS) { event->xRc = HvLpEvent_Rc_SubtypeError; cevent->subtype_result_code = viorc_openRejected; /* * Flag state here since we can't printk while holding * a spinlock. */ reject = 1; } else { pi = &port_info[port]; if ((pi->lp != HvLpIndexInvalid) && (pi->lp != event->xSourceLp)) { /* * If this is tty is already connected to a different * partition, fail. */ event->xRc = HvLpEvent_Rc_SubtypeError; cevent->subtype_result_code = viorc_openRejected; reject = 2; } else { pi->lp = event->xSourceLp; event->xRc = HvLpEvent_Rc_Good; cevent->subtype_result_code = viorc_good; pi->seq = pi->ack = 0; reject = 0; } } spin_unlock_irqrestore(&consolelock, flags); if (reject == 1) printk(VIOCONS_KERN_WARN "open rejected: bad virtual tty.\n"); else if (reject == 2) printk(VIOCONS_KERN_WARN "open rejected: console in exclusive use by another partition.\n"); /* Return the acknowledgement */ HvCallEvent_ackLpEvent(event);}/* * Handle a close charLpEvent. This should ONLY be an Interrupt because the * virtual console should never actually issue a close event to the hypervisor * because the virtual console never goes away. A close event coming from the * hypervisor simply means that there are no client consoles connected to the * virtual console. * * Regardless of the number of connections masqueraded on the other side of * the hypervisor ONLY ONE close event should be called to accompany the ONE * open event that is called. The close event should ONLY be called when NO * MORE connections (masqueraded or not) exist on the other side of the * hypervisor. */static void vioHandleCloseEvent(struct HvLpEvent *event){ unsigned long flags; struct viocharlpevent *cevent = (struct viocharlpevent *)event; u8 port = cevent->virtual_device; if (event->xFlags.xFunction == HvLpEvent_Function_Int) { if (port >= VTTY_PORTS) { printk(VIOCONS_KERN_WARN "close message from invalid virtual device.\n"); return; } /* For closes, just mark the console partition invalid */ spin_lock_irqsave(&consolelock, flags); /* Got the lock, don't cause console output */ if (port_info[port].lp == event->xSourceLp) port_info[port].lp = HvLpIndexInvalid; spin_unlock_irqrestore(&consolelock, flags); printk(VIOCONS_KERN_INFO "close from %d\n", event->xSourceLp); } else printk(VIOCONS_KERN_WARN "got unexpected close acknowlegement\n");}/* * Handle a config charLpEvent. Could be either interrupt or ack */static void vioHandleConfig(struct HvLpEvent *event){ struct viocharlpevent *cevent = (struct viocharlpevent *)event; HvCall_writeLogBuffer(cevent->data, cevent->len); if (cevent->data[0] == 0x01) printk(VIOCONS_KERN_INFO "window resized to %d: %d: %d: %d\n", cevent->data[1], cevent->data[2], cevent->data[3], cevent->data[4]); else printk(VIOCONS_KERN_WARN "unknown config event\n");}/* * Handle a data charLpEvent. */static void vioHandleData(struct HvLpEvent *event){ struct tty_struct *tty; unsigned long flags; struct viocharlpevent *cevent = (struct viocharlpevent *)event; struct port_info *pi; int index; u8 port = cevent->virtual_device; if (port >= VTTY_PORTS) { printk(VIOCONS_KERN_WARN "data on invalid virtual device %d\n", port); return; } /* * Hold the spinlock so that we don't take an interrupt that * changes tty between the time we fetch the port_info * pointer and the time we paranoia check. */ spin_lock_irqsave(&consolelock, flags); pi = &port_info[port]; /* * Change 05/01/2003 - Ryan Arnold: If a partition other than * the current exclusive partition tries to send us data * events then just drop them on the floor because we don't * want his stinking data. He isn't authorized to receive * data because he wasn't the first one to get the console, * therefore he shouldn't be allowed to send data either. * This will work without an iSeries fix. */ if (pi->lp != event->xSourceLp) { spin_unlock_irqrestore(&consolelock, flags); return; } tty = pi->tty; if (tty == NULL) { spin_unlock_irqrestore(&consolelock, flags); printk(VIOCONS_KERN_WARN "no tty for virtual device %d\n", port); return; } if (tty->magic != TTY_MAGIC) { spin_unlock_irqrestore(&consolelock, flags); printk(VIOCONS_KERN_WARN "tty bad magic\n"); return; } /* * Just to be paranoid, make sure the tty points back to this port */ pi = (struct port_info *)tty->driver_data; if (!pi || viotty_paranoia_check(pi, tty->name, "vioHandleData")) { spin_unlock_irqrestore(&consolelock, flags); return; } spin_unlock_irqrestore(&consolelock, flags); /* * Change 07/21/2003 - Ryan Arnold: functionality added to * support sysrq utilizing ^O as the sysrq key. The sysrq * functionality will only work if built into the kernel and * then only if sysrq is enabled through the proc filesystem. */ for (index = 0; index < cevent->len; index++) {#ifdef CONFIG_MAGIC_SYSRQ if (sysrq_enabled) { /* 0x0f is the ascii character for ^O */ if (cevent->data[index] == '\x0f') { vio_sysrq_pressed = 1; /* * continue because we don't want to add * the sysrq key into the data string. */ continue; } else if (vio_sysrq_pressed) { handle_sysrq(cevent->data[index], NULL, tty); vio_sysrq_pressed = 0; /* * continue because we don't want to add * the sysrq sequence into the data string. */ continue; } }#endif /* * The sysrq sequence isn't included in this check if * sysrq is enabled and compiled into the kernel because * the sequence will never get inserted into the buffer. * Don't attempt to copy more data into the buffer than we * have room for because it would fail without indication. */ if ((tty->flip.count + 1) > TTY_FLIPBUF_SIZE) { printk(VIOCONS_KERN_WARN "input buffer overflow!\n"); break; } tty_insert_flip_char(tty, cevent->data[index], TTY_NORMAL); } /* if cevent->len == 0 then no data was added to the buffer and flip.count == 0 */ if (tty->flip.count) /* The next call resets flip.count when the data is flushed. */ tty_flip_buffer_push(tty);}/* * Handle an ack charLpEvent. */static void vioHandleAck(struct HvLpEvent *event){ struct viocharlpevent *cevent = (struct viocharlpevent *)event; unsigned long flags; u8 port = cevent->virtual_device; if (port >= VTTY_PORTS) { printk(VIOCONS_KERN_WARN "data on invalid virtual device\n"); return; } spin_lock_irqsave(&consolelock, flags); port_info[port].ack = event->xCorrelationToken; spin_unlock_irqrestore(&consolelock, flags); if (port_info[port].used) send_buffers(&port_info[port]);}/* * Handle charLpEvents and route to the appropriate routine */static void vioHandleCharEvent(struct HvLpEvent *event){ int charminor; if (event == NULL) return; charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; switch (charminor) { case viocharopen: vioHandleOpenEvent(event); break; case viocharclose: vioHandleCloseEvent(event); break; case viochardata: vioHandleData(event); break; case viocharack: vioHandleAck(event); break; case viocharconfig: vioHandleConfig(event); break; default: if ((event->xFlags.xFunction == HvLpEvent_Function_Int) && (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)) { event->xRc = HvLpEvent_Rc_InvalidSubtype; HvCallEvent_ackLpEvent(event); } }}/* * Send an open event */static int send_open(HvLpIndex remoteLp, void *sem){ return HvCallEvent_signalLpEventFast(remoteLp, HvLpEvent_Type_VirtualIo, viomajorsubtype_chario | viocharopen, HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, viopath_sourceinst(remoteLp), viopath_targetinst(remoteLp), (u64)(unsigned long)sem, VIOVERSION << 16, 0, 0, 0, 0);}static struct tty_operations serial_ops = { .open = viotty_open, .close = viotty_close, .write = viotty_write, .put_char = viotty_put_char, .write_room = viotty_write_room, .chars_in_buffer = viotty_chars_in_buffer, .ioctl = viotty_ioctl,};static int __init viocons_init2(void){ atomic_t wait_flag; int rc; /* +2 for fudge */ rc = viopath_open(HvLpConfig_getPrimaryLpIndex(), viomajorsubtype_chario, VIOCHAR_WINDOW + 2); if (rc) printk(VIOCONS_KERN_WARN "error opening to primary %d\n", rc); if (viopath_hostLp == HvLpIndexInvalid) vio_set_hostlp(); /* * And if the primary is not the same as the hosting LP, open to the * hosting lp */ if ((viopath_hostLp != HvLpIndexInvalid) && (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) { printk(VIOCONS_KERN_INFO "open path to hosting (%d)\n", viopath_hostLp); rc = viopath_open(viopath_hostLp, viomajorsubtype_chario, VIOCHAR_WINDOW + 2); /* +2 for fudge */ if (rc) printk(VIOCONS_KERN_WARN "error opening to partition %d: %d\n", viopath_hostLp, rc); } if (vio_setHandler(viomajorsubtype_chario, vioHandleCharEvent) < 0) printk(VIOCONS_KERN_WARN "error seting handler for console events!\n"); /* * First, try to open the console to the hosting lp. * Wait on a semaphore for the response. */ atomic_set(&wait_flag, 0); if ((viopath_isactive(viopath_hostLp)) && (send_open(viopath_hostLp, (void *)&wait_flag) == 0)) { printk(VIOCONS_KERN_INFO "hosting partition %d\n", viopath_hostLp); while (atomic_read(&wait_flag) == 0) mb(); atomic_set(&wait_flag, 0); } /* * If we don't have an active console, try the primary */ if ((!viopath_isactive(port_info[0].lp)) && (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) && (send_open(HvLpConfig_getPrimaryLpIndex(), (void *)&wait_flag) == 0)) { printk(VIOCONS_KERN_INFO "opening console to primary partition\n"); while (atomic_read(&wait_flag) == 0) mb(); } /* Initialize the tty_driver structure */ viotty_driver = alloc_tty_driver(VTTY_PORTS); viotty_driver->owner = THIS_MODULE; viotty_driver->driver_name = "vioconsole"; viotty_driver->devfs_name = "vcs/"; viotty_driver->name = "tty"; viotty_driver->name_base = 1; viotty_driver->major = TTY_MAJOR; viotty_driver->minor_start = 1; viotty_driver->type = TTY_DRIVER_TYPE_CONSOLE; viotty_driver->subtype = 1; viotty_driver->init_termios = tty_std_termios; viotty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; tty_set_operations(viotty_driver, &serial_ops); if (tty_register_driver(viotty_driver)) { printk(VIOCONS_KERN_WARN "couldn't register console driver\n"); put_tty_driver(viotty_driver); viotty_driver = NULL; } viocons_init_cfu_buffer(); unregister_console(&viocons_early); register_console(&viocons); return 0;}static int __init viocons_init(void){ int i; printk(VIOCONS_KERN_INFO "registering console\n"); for (i = 0; i < VTTY_PORTS; i++) { port_info[i].lp = HvLpIndexInvalid; port_info[i].magic = VIOTTY_MAGIC; } HvCall_setLogBufferFormatAndCodepage(HvCall_LogBuffer_ASCII, 437); register_console(&viocons_early); return 0;}console_initcall(viocons_init);module_init(viocons_init2);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?