hvc_console.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 880 行 · 第 1/2 页

C
880
字号
		hvc_kick();	return written;}/* * This is actually a contract between the driver and the tty layer outlining * how much write room the driver can guarentee will be sent OR BUFFERED.  This * driver MUST honor the return value. */static int hvc_write_room(struct tty_struct *tty){	struct hvc_struct *hp = tty->driver_data;	if (!hp)		return -1;	return N_OUTBUF - hp->n_outbuf;}static int hvc_chars_in_buffer(struct tty_struct *tty){	struct hvc_struct *hp = tty->driver_data;	if (!hp)		return -1;	return hp->n_outbuf;}#define HVC_POLL_READ	0x00000001#define HVC_POLL_WRITE	0x00000002#define HVC_POLL_QUICK	0x00000004static int hvc_poll(struct hvc_struct *hp){	struct tty_struct *tty;	int i, n, poll_mask = 0;	char buf[N_INBUF] __ALIGNED__;	unsigned long flags;	int read_total = 0;	spin_lock_irqsave(&hp->lock, flags);	/* Push pending writes */	if (hp->n_outbuf > 0)		hvc_push(hp);	/* Reschedule us if still some write pending */	if (hp->n_outbuf > 0)		poll_mask |= HVC_POLL_WRITE;	/* No tty attached, just skip */	tty = hp->tty;	if (tty == NULL)		goto bail;	/* Now check if we can get data (are we throttled ?) */	if (test_bit(TTY_THROTTLED, &tty->flags))		goto throttled;	/* If we aren't interrupt driven and aren't throttled, we always	 * request a reschedule	 */	if (hp->irq == NO_IRQ)		poll_mask |= HVC_POLL_READ;	/* Read data if any */	for (;;) {		int count = N_INBUF;		if (count > (TTY_FLIPBUF_SIZE - tty->flip.count))			count = TTY_FLIPBUF_SIZE - tty->flip.count;		/* If flip is full, just reschedule a later read */		if (count == 0) {			poll_mask |= HVC_POLL_READ;			break;		}		n = hvc_get_chars(hp->vtermno, buf, count);		if (n <= 0) {			/* Hangup the tty when disconnected from host */			if (n == -EPIPE) {				spin_unlock_irqrestore(&hp->lock, flags);				tty_hangup(tty);				spin_lock_irqsave(&hp->lock, flags);			}			break;		}		for (i = 0; i < n; ++i) {#ifdef CONFIG_MAGIC_SYSRQ			/* Handle the SysRq Hack */			if (buf[i] == '\x0f') {	/* ^O -- should support a sequence */				sysrq_pressed = 1;				continue;			} else if (sysrq_pressed) {				handle_sysrq(buf[i], NULL, tty);				sysrq_pressed = 0;				continue;			}#endif /* CONFIG_MAGIC_SYSRQ */			tty_insert_flip_char(tty, buf[i], 0);		}		if (tty->flip.count)			tty_schedule_flip(tty);		/*		 * Account for the total amount read in one loop, and if above		 * 64 bytes, we do a quick schedule loop to let the tty grok the		 * data and eventually throttle us.		 */		read_total += n;		if (read_total >= 64) {			poll_mask |= HVC_POLL_QUICK;			break;		}	} throttled:	/* Wakeup write queue if necessary */	if (hp->do_wakeup) {		hp->do_wakeup = 0;		tty_wakeup(tty);	} bail:	spin_unlock_irqrestore(&hp->lock, flags);	return poll_mask;}#if defined(CONFIG_XMON) && defined(CONFIG_SMP)extern cpumask_t cpus_in_xmon;#elsestatic const cpumask_t cpus_in_xmon = CPU_MASK_NONE;#endif/* * This kthread is either polling or interrupt driven.  This is determined by * calling hvc_poll() who determines whether a console adapter support * interrupts. */int khvcd(void *unused){	int poll_mask;	struct hvc_struct *hp;	__set_current_state(TASK_RUNNING);	do {		poll_mask = 0;		hvc_kicked = 0;		wmb();		if (cpus_empty(cpus_in_xmon)) {			spin_lock(&hvc_structs_lock);			list_for_each_entry(hp, &hvc_structs, next) {				/*hp = list_entry(node, struct hvc_struct, * next); */				poll_mask |= hvc_poll(hp);			}			spin_unlock(&hvc_structs_lock);		} else			poll_mask |= HVC_POLL_READ;		if (hvc_kicked)			continue;		if (poll_mask & HVC_POLL_QUICK) {			yield();			continue;		}		set_current_state(TASK_INTERRUPTIBLE);		if (!hvc_kicked) {			if (poll_mask == 0)				schedule();			else				schedule_timeout(TIMEOUT);		}		__set_current_state(TASK_RUNNING);	} while (!kthread_should_stop());	return 0;}static struct tty_operations hvc_ops = {	.open = hvc_open,	.close = hvc_close,	.write = hvc_write,	.hangup = hvc_hangup,	.unthrottle = hvc_unthrottle,	.write_room = hvc_write_room,	.chars_in_buffer = hvc_chars_in_buffer,};char hvc_driver_name[] = "hvc_console";static struct vio_device_id hvc_driver_table[] __devinitdata= {	{"serial", "hvterm1"},	{ 0, }};MODULE_DEVICE_TABLE(vio, hvc_driver_table);/* callback when the kboject ref count reaches zero. */static void destroy_hvc_struct(struct kobject *kobj){	struct hvc_struct *hp = container_of(kobj, struct hvc_struct, kobj);	unsigned long flags;	spin_lock(&hvc_structs_lock);	spin_lock_irqsave(&hp->lock, flags);	list_del(&(hp->next));	spin_unlock_irqrestore(&hp->lock, flags);	spin_unlock(&hvc_structs_lock);	kfree(hp);}static struct kobj_type hvc_kobj_type = {	.release = destroy_hvc_struct,};static int __devinit hvc_probe(		struct vio_dev *dev,		const struct vio_device_id *id){	struct hvc_struct *hp;	/* probed with invalid parameters. */	if (!dev || !id)		return -EPERM;	hp = kmalloc(sizeof(*hp), GFP_KERNEL);	if (!hp)		return -ENOMEM;	memset(hp, 0x00, sizeof(*hp));	hp->vtermno = dev->unit_address;	hp->vdev = dev;	hp->vdev->dev.driver_data = hp;	hp->irq = dev->irq;	kobject_init(&hp->kobj);	hp->kobj.ktype = &hvc_kobj_type;	hp->lock = SPIN_LOCK_UNLOCKED;	spin_lock(&hvc_structs_lock);	hp->index = ++hvc_count;	list_add_tail(&(hp->next), &hvc_structs);	spin_unlock(&hvc_structs_lock);	return 0;}static int __devexit hvc_remove(struct vio_dev *dev){	struct hvc_struct *hp = dev->dev.driver_data;	unsigned long flags;	struct kobject *kobjp;	struct tty_struct *tty;	spin_lock_irqsave(&hp->lock, flags);	tty = hp->tty;	kobjp = &hp->kobj;	if (hp->index < MAX_NR_HVC_CONSOLES)		vtermnos[hp->index] = -1;	/* Don't whack hp->irq because tty_hangup() will need to free the irq. */	spin_unlock_irqrestore(&hp->lock, flags);	/*	 * We 'put' the instance that was grabbed when the kobject instance	 * was intialized using kobject_init().  Let the last holder of this	 * kobject cause it to be removed, which will probably be the tty_hangup	 * below.	 */	kobject_put(kobjp);	/*	 * This function call will auto chain call hvc_hangup.  The tty should	 * always be valid at this time unless a simultaneous tty close already	 * cleaned up the hvc_struct.	 */	if (tty)		tty_hangup(tty);	return 0;}static struct vio_driver hvc_vio_driver = {	.name		= hvc_driver_name,	.id_table	= hvc_driver_table,	.probe		= hvc_probe,	.remove		= hvc_remove,};/* Driver initialization.  Follow console initialization.  This is where the TTY * interfaces start to become available. */int __init hvc_init(void){	int rc;	/* We need more than num_vterms adapters due to hotplug additions. */	hvc_driver = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS);	/* hvc_driver = alloc_tty_driver(num_vterms); */	if (!hvc_driver)		return -ENOMEM;	hvc_driver->owner = THIS_MODULE;	hvc_driver->devfs_name = "hvc/";	hvc_driver->driver_name = "hvc";	hvc_driver->name = "hvc";	hvc_driver->major = HVC_MAJOR;	hvc_driver->minor_start = HVC_MINOR;	hvc_driver->type = TTY_DRIVER_TYPE_SYSTEM;	hvc_driver->init_termios = tty_std_termios;	hvc_driver->flags = TTY_DRIVER_REAL_RAW;	tty_set_operations(hvc_driver, &hvc_ops);	if (tty_register_driver(hvc_driver))		panic("Couldn't register hvc console driver\n");	/* Always start the kthread because there can be hotplug vty adapters	 * added later. */	hvc_task = kthread_run(khvcd, NULL, "khvcd");	if (IS_ERR(hvc_task)) {		panic("Couldn't create kthread for console.\n");		put_tty_driver(hvc_driver);		return -EIO;	}	/* Register as a vio device to receive callbacks */	rc = vio_register_driver(&hvc_vio_driver);	return rc;}/* This isn't particularily necessary due to this being a console driver but it * is nice to be thorough */static void __exit hvc_exit(void){	kthread_stop(hvc_task);	vio_unregister_driver(&hvc_vio_driver);	tty_unregister_driver(hvc_driver);	/* return tty_struct instances allocated in hvc_init(). */	put_tty_driver(hvc_driver);}/* * Console APIs, NOT TTY.  These APIs are available immediately when * hvc_console_setup() finds adapters. *//* * hvc_instantiate() is an early console discovery method which locates consoles * prior to the vio subsystem discovering them.  Hotplugged vty adapters do NOT * get an hvc_instantiate() callback since the appear after early console init. */int hvc_instantiate(uint32_t vtermno, int index){	if (index < 0 || index >= MAX_NR_HVC_CONSOLES)		return -1;	if (vtermnos[index] != -1)		return -1;	vtermnos[index] = vtermno;	return 0;}void hvc_console_print(struct console *co, const char *b, unsigned count){	char c[16] __ALIGNED__;	unsigned i = 0, n = 0;	int r, donecr = 0;	/* Console access attempt outside of acceptable console range. */	if (co->index >= MAX_NR_HVC_CONSOLES)		return;	/* This console adapter was removed so it is not useable. */	if (vtermnos[co->index] < 0)		return;	while (count > 0 || i > 0) {		if (count > 0 && i < sizeof(c)) {			if (b[n] == '\n' && !donecr) {				c[i++] = '\r';				donecr = 1;			} else {				c[i++] = b[n++];				donecr = 0;				--count;			}		} else {			r = hvc_put_chars(vtermnos[co->index], c, i);			if (r < 0) {				/* throw away chars on error */				i = 0;			} else if (r > 0) {				i -= r;				if (i > 0)					memmove(c, c+r, i);			}		}	}}static struct tty_driver *hvc_console_device(struct console *c, int *index){	*index = c->index;	return hvc_driver;}static int __init hvc_console_setup(struct console *co, char *options){	return 0;}struct console hvc_con_driver = {	.name		= "hvc",	.write		= hvc_console_print,	.device		= hvc_console_device,	.setup		= hvc_console_setup,	.flags		= CON_PRINTBUFFER,	.index		= -1,};/* Early console initialization.  Preceeds driver initialization. */static int __init hvc_console_init(void){	int i;	for (i=0; i<MAX_NR_HVC_CONSOLES; i++)		vtermnos[i] = -1;	num_vterms = hvc_find_vtys();	register_console(&hvc_con_driver);	return 0;}console_initcall(hvc_console_init);module_init(hvc_init);module_exit(hvc_exit);

⌨️ 快捷键说明

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