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 + -
显示快捷键?