greybus: ap message loop added.
This commit is contained in:
parent
27fb83109a
commit
de536e3094
|
@ -1,4 +1,11 @@
|
|||
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
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -176,8 +176,16 @@ void greybus_deregister(struct greybus_driver *driver);
|
|||
|
||||
int greybus_disabled(void);
|
||||
|
||||
int greybus_debugfs_init(void);
|
||||
void greybus_debugfs_cleanup(void);
|
||||
|
||||
/* Internal functions to gb module, move to internal .h file eventually. */
|
||||
|
||||
int gb_new_ap_msg(u8 *data, int length);
|
||||
int gb_thread_init(void);
|
||||
void gb_thread_destroy(void);
|
||||
int gb_debugfs_init(void);
|
||||
void gb_debugfs_cleanup(void);
|
||||
|
||||
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* __LINUX_GREYBUS_H */
|
||||
|
|
Loading…
Reference in New Issue