Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 837dcfaf authored by Milton Miller's avatar Milton Miller Committed by Linus Torvalds
Browse files

[PATCH] hvc_console: Rearrange code



Milton Miller has done a lot of work to clean up our hvc_console code.

One of the important things the following patch series does is separate the
VIO layer from the hvc_console code.  With the VIO specific code removed any
ppc64 platform, or even any architecture, can use hvc_console as a generic
polling console.  You simply have to supply a get_chars and put_chars method
and hvc_console does the rest of the work.  You can even use it for an
interrupt driven console.

This patch:

Rearrange the code in drivers/char/hvc_console.c to make future patches
smaller.  No actual code changes, just ordering of the functions in the file.

Signed-off-by: default avatarMilton Miller <miltonm@bga.com>
Signed-off-by: default avatarAnton Blanchard <anton@samba.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 5cee73fa
Loading
Loading
Loading
Loading
+142 −142
Original line number Original line Diff line number Diff line
@@ -61,16 +61,21 @@
 */
 */
#define HVC_ALLOC_TTY_ADAPTERS	8
#define HVC_ALLOC_TTY_ADAPTERS	8


static struct tty_driver *hvc_driver;
#ifdef CONFIG_MAGIC_SYSRQ
static int sysrq_pressed;
#endif

#define N_OUTBUF	16
#define N_OUTBUF	16
#define N_INBUF		16
#define N_INBUF		16


#define __ALIGNED__	__attribute__((__aligned__(8)))
#define __ALIGNED__	__attribute__((__aligned__(8)))


static struct tty_driver *hvc_driver;
static struct task_struct *hvc_task;

/* Picks up late kicks after list walk but before schedule() */
static int hvc_kicked;

#ifdef CONFIG_MAGIC_SYSRQ
static int sysrq_pressed;
#endif

struct hvc_struct {
struct hvc_struct {
	spinlock_t lock;
	spinlock_t lock;
	int index;
	int index;
@@ -96,6 +101,41 @@ static struct list_head hvc_structs = LIST_HEAD_INIT(hvc_structs);
 */
 */
static DEFINE_SPINLOCK(hvc_structs_lock);
static DEFINE_SPINLOCK(hvc_structs_lock);


/*
 * This value is used to associate a tty->index value to a hvc_struct based
 * upon order of exposure via hvc_probe().
 */
static int hvc_count = -1;

/*
 * Do not call this function with either the hvc_strucst_lock or the hvc_struct
 * lock held.  If successful, this function increments the kobject reference
 * count against the target hvc_struct so it should be released when finished.
 */
struct hvc_struct *hvc_get_by_index(int index)
{
	struct hvc_struct *hp;
	unsigned long flags;

	spin_lock(&hvc_structs_lock);

	list_for_each_entry(hp, &hvc_structs, next) {
		spin_lock_irqsave(&hp->lock, flags);
		if (hp->index == index) {
			kobject_get(&hp->kobj);
			spin_unlock_irqrestore(&hp->lock, flags);
			spin_unlock(&hvc_structs_lock);
			return hp;
		}
		spin_unlock_irqrestore(&hp->lock, flags);
	}
	hp = NULL;

	spin_unlock(&hvc_structs_lock);
	return hp;
}


/*
/*
 * Initial console vtermnos for console API usage prior to full console
 * Initial console vtermnos for console API usage prior to full console
 * initialization.  Any vty adapter outside this range will not have usable
 * initialization.  Any vty adapter outside this range will not have usable
@@ -107,16 +147,98 @@ static uint32_t vtermnos[MAX_NR_HVC_CONSOLES];
/* Used for accounting purposes */
/* Used for accounting purposes */
static int num_vterms = 0;
static int num_vterms = 0;


static struct task_struct *hvc_task;
/*
 * Console APIs, NOT TTY.  These APIs are available immediately when
 * hvc_console_setup() finds adapters.
 */

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);


/*
/*
 * This value is used to associate a tty->index value to a hvc_struct based
 * hvc_instantiate() is an early console discovery method which locates consoles
 * upon order of exposure via hvc_probe().
 * prior to the vio subsystem discovering them.  Hotplugged vty adapters do NOT
 * get an hvc_instantiate() callback since the appear after early console init.
 */
 */
static int hvc_count = -1;
int hvc_instantiate(uint32_t vtermno, int index)
{
	if (index < 0 || index >= MAX_NR_HVC_CONSOLES)
		return -1;


/* Picks up late kicks after list walk but before schedule() */
	if (vtermnos[index] != -1)
static int hvc_kicked;
		return -1;

	vtermnos[index] = vtermno;
	return 0;
}


/* Wake the sleeping khvcd */
/* Wake the sleeping khvcd */
static void hvc_kick(void)
static void hvc_kick(void)
@@ -140,34 +262,6 @@ static void hvc_unthrottle(struct tty_struct *tty)
	hvc_kick();
	hvc_kick();
}
}


/*
 * Do not call this function with either the hvc_strucst_lock or the hvc_struct
 * lock held.  If successful, this function increments the kobject reference
 * count against the target hvc_struct so it should be released when finished.
 */
struct hvc_struct *hvc_get_by_index(int index)
{
	struct hvc_struct *hp;
	unsigned long flags;

	spin_lock(&hvc_structs_lock);

	list_for_each_entry(hp, &hvc_structs, next) {
		spin_lock_irqsave(&hp->lock, flags);
		if (hp->index == index) {
			kobject_get(&hp->kobj);
			spin_unlock_irqrestore(&hp->lock, flags);
			spin_unlock(&hvc_structs_lock);
			return hp;
		}
		spin_unlock_irqrestore(&hp->lock, flags);
	}
	hp = NULL;

	spin_unlock(&hvc_structs_lock);
	return hp;
}

/*
/*
 * The TTY interface won't be used until after the vio layer has exposed the vty
 * The TTY interface won't be used until after the vio layer has exposed the vty
 * adapter to the kernel.
 * adapter to the kernel.
@@ -577,14 +671,6 @@ static struct tty_operations hvc_ops = {
	.chars_in_buffer = hvc_chars_in_buffer,
	.chars_in_buffer = hvc_chars_in_buffer,
};
};


char hvc_driver_name[] = "hvc_console";

static struct vio_device_id hvc_driver_table[] __devinitdata= {
	{"serial", "hvterm1"},
	{ NULL, }
};
MODULE_DEVICE_TABLE(vio, hvc_driver_table);

/* callback when the kboject ref count reaches zero. */
/* callback when the kboject ref count reaches zero. */
static void destroy_hvc_struct(struct kobject *kobj)
static void destroy_hvc_struct(struct kobject *kobj)
{
{
@@ -674,6 +760,14 @@ static int __devexit hvc_remove(struct vio_dev *dev)
	return 0;
	return 0;
}
}


char hvc_driver_name[] = "hvc_console";

static struct vio_device_id hvc_driver_table[] __devinitdata= {
	{"serial", "hvterm1"},
	{ NULL, }
};
MODULE_DEVICE_TABLE(vio, hvc_driver_table);

static struct vio_driver hvc_vio_driver = {
static struct vio_driver hvc_vio_driver = {
	.name		= hvc_driver_name,
	.name		= hvc_driver_name,
	.id_table	= hvc_driver_table,
	.id_table	= hvc_driver_table,
@@ -721,6 +815,7 @@ int __init hvc_init(void)


	return rc;
	return rc;
}
}
module_init(hvc_init);


/* This isn't particularily necessary due to this being a console driver but it
/* This isn't particularily necessary due to this being a console driver but it
 * is nice to be thorough */
 * is nice to be thorough */
@@ -733,99 +828,4 @@ static void __exit hvc_exit(void)
	/* return tty_struct instances allocated in hvc_init(). */
	/* return tty_struct instances allocated in hvc_init(). */
	put_tty_driver(hvc_driver);
	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);
module_exit(hvc_exit);