Commit de536e30 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

greybus: ap message loop added.

parent 27fb8310
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
greybus-y := core.o gbuf.o debugfs.o i2c-gb.o gpio-gb.o sdio-gb.o uart-gb.o
greybus-y :=	core.o		\
		gbuf.o		\
		debugfs.o	\
		ap.o		\
		i2c-gb.o	\
		gpio-gb.o	\
		sdio-gb.o	\
		uart-gb.o

obj-m += greybus.o
obj-m += es1-ap-usb.o
+125 −0
Original line number Diff line number Diff line
/*
 * Greybus "AP" message loop handling
 *
 * Copyright 2014 Google Inc.
 *
 * Released under the GPLv2 only.
 */

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/types.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/kthread.h>
#include <linux/device.h>
#include "greybus.h"

struct ap_msg {
	u8 *data;
	int size;
	struct list_head list;
};

static LIST_HEAD(ap_msg_list);
static spinlock_t ap_msg_list_lock;
static struct task_struct *ap_thread;
static wait_queue_head_t ap_wait;

static struct ap_msg *get_ap_msg(void)
{
	struct ap_msg *ap_msg;
	unsigned long flags;

	spin_lock_irqsave(&ap_msg_list_lock, flags);

	ap_msg = list_first_entry_or_null(&ap_msg_list, struct ap_msg, list);
	if (ap_msg != NULL)
		list_del(&ap_msg->list);
	spin_unlock_irqrestore(&ap_msg_list_lock, flags);

	return ap_msg;
}

static int ap_process_loop(void *data)
{
	struct ap_msg *ap_msg;

	while (!kthread_should_stop()) {
		wait_event_interruptible(ap_wait, kthread_should_stop());

		if (kthread_should_stop())
			break;

		/* Get some data off of the ap list and process it */
		ap_msg = get_ap_msg();
		if (!ap_msg)
			continue;

		// FIXME - process the message

		/* clean the message up */
		kfree(ap_msg->data);
		kfree(ap_msg);
	}
	return 0;
}

int gb_new_ap_msg(u8 *data, int size)
{
	struct ap_msg *ap_msg;
	unsigned long flags;

	/*
	 * Totally naive copy the message into a new structure that we slowly
	 * create and add it to the list.  Let's get this working, the odds of
	 * this being any "slow path" for AP messages is really low at this
	 * point in time, but you never know, so this comment is here to point
	 * out that maybe we should use a slab allocator, or even just not copy
	 * the data, but use it directly and force the urbs to be "new" each
	 * time.
	 */

	/* Note - this can, and will, be called in interrupt context. */
	ap_msg = kmalloc(sizeof(*ap_msg), GFP_ATOMIC);
	if (!ap_msg)
		return -ENOMEM;
	ap_msg->data = kmalloc(size, GFP_ATOMIC);
	if (!ap_msg->data) {
		kfree(ap_msg);
		return -ENOMEM;
	}
	memcpy(ap_msg->data, data, size);
	ap_msg->size = size;

	spin_lock_irqsave(&ap_msg_list_lock, flags);
	list_add(&ap_msg->list, &ap_msg_list);
	spin_unlock_irqrestore(&ap_msg_list_lock, flags);

	/* kick our thread to handle the message */
	wake_up_interruptible(&ap_wait);

	return 0;
}

int gb_thread_init(void)
{
	init_waitqueue_head(&ap_wait);
	spin_lock_init(&ap_msg_list_lock);

	ap_thread = kthread_run(ap_process_loop, NULL, "greybus_ap");
	if (IS_ERR(ap_thread))
		return PTR_ERR(ap_thread);

	return 0;
}

void gb_thread_destroy(void)
{
	kthread_stop(ap_thread);
}

+11 −3
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/device.h>

#include "greybus.h"
@@ -199,7 +200,7 @@ static int __init gb_init(void)
{
	int retval;

	retval = greybus_debugfs_init();
	retval = gb_debugfs_init();
	if (retval)
		return retval;

@@ -207,6 +208,10 @@ static int __init gb_init(void)
	if (retval)
		goto error_bus;

	retval = gb_thread_init();
	if (retval)
		goto error_thread;

	// FIXME - more gb core init goes here

	retval = gb_tty_init();
@@ -216,10 +221,13 @@ static int __init gb_init(void)
	return 0;

error_tty:
	gb_thread_destroy();

error_thread:
	bus_unregister(&greybus_bus_type);

error_bus:
	greybus_debugfs_cleanup();
	gb_debugfs_cleanup();

	return retval;
}
@@ -228,7 +236,7 @@ static void __exit gb_exit(void)
{
	gb_tty_exit();
	bus_unregister(&greybus_bus_type);
	greybus_debugfs_cleanup();
	gb_debugfs_cleanup();
}

module_init(gb_init);
+2 −2
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@

static struct dentry *gb_debug_root;

int greybus_debugfs_init(void)
int gb_debugfs_init(void)
{
	gb_debug_root = debugfs_create_dir("greybus", NULL);
	if (!gb_debug_root)
@@ -28,7 +28,7 @@ int greybus_debugfs_init(void)
	return 0;
}

void greybus_debugfs_cleanup(void)
void gb_debugfs_cleanup(void)
{
	debugfs_remove_recursive(gb_debug_root);
}
+63 −1
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/usb.h>

#include "greybus.h"

static const struct usb_device_id id_table[] = {
	{ USB_DEVICE(0x0000, 0x0000) },		// FIXME
@@ -34,6 +34,68 @@ struct es1_ap_dev {
 */
static struct es1_ap_dev *es1_ap_dev;

static void ap_in_callback(struct urb *urb)
{
	struct device *dev = &urb->dev->dev;
	int status = urb->status;
	int retval;

	switch (status) {
	case 0:
		break;
	case -EOVERFLOW:
		dev_err(dev, "%s: overflow actual length is %d\n",
			__func__, urb->actual_length);
	case -ECONNRESET:
	case -ENOENT:
	case -ESHUTDOWN:
	case -EILSEQ:
		/* device is gone, stop sending */
		return;
	default:
		dev_err(dev, "%s: unknown status %d\n", __func__, status);
		goto exit;
	}

	/* We have a message, create a new message structure, add it to the
	 * list, and wake up our thread that will process the messages.
	 */
	gb_new_ap_msg(urb->transfer_buffer, urb->actual_length);

exit:
	/* resubmit the urb to get more messages */
	retval = usb_submit_urb(urb, GFP_ATOMIC);
	if (retval)
		dev_err(dev, "Can not submit urb for AP data: %d\n", retval);
}

static void ap_out_callback(struct urb *urb)
{
	struct device *dev = &urb->dev->dev;
	int status = urb->status;

	switch (status) {
	case 0:
		break;
	case -EOVERFLOW:
		dev_err(dev, "%s: overflow actual length is %d\n",
			__func__, urb->actual_length);
	case -ECONNRESET:
	case -ENOENT:
	case -ESHUTDOWN:
	case -EILSEQ:
		/* device is gone, stop sending */
		return;
	default:
		dev_err(dev, "%s: unknown status %d\n", __func__, status);
		goto exit;
	}

	// FIXME - queue up next AP message to send???
exit:
	return;
}


static int ap_probe(struct usb_interface *interface,
		    const struct usb_device_id *id)
Loading