#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
-#include <linux/kthread.h>
+#include <linux/workqueue.h>
#include <linux/device.h>
#include "svc_msg.h"
#include "greybus_manifest.h"
}
EXPORT_SYMBOL_GPL(gb_new_ap_msg);
-int gb_thread_init(void)
+int gb_ap_init(void)
{
ap_workqueue = alloc_workqueue("greybus_ap", 0, 1);
if (!ap_workqueue)
return 0;
}
-void gb_thread_destroy(void)
+void gb_ap_exit(void)
{
destroy_workqueue(ap_workqueue);
}
goto error_bus;
}
- retval = gb_thread_init();
+ retval = gb_ap_init();
if (retval) {
- pr_err("gb_thread_init failed\n");
- goto error_thread;
+ pr_err("gb_ap_init failed\n");
+ goto error_ap;
}
- // FIXME - more gb core init goes here
+ retval = gb_gbuf_init();
+ if (retval) {
+ pr_err("gb_gbuf_init failed\n");
+ goto error_gbuf;
+ }
retval = gb_tty_init();
if (retval) {
return 0;
error_tty:
- gb_thread_destroy();
+ gb_gbuf_exit();
+
+error_gbuf:
+ gb_ap_exit();
-error_thread:
+error_ap:
bus_unregister(&greybus_bus_type);
error_bus:
static void __exit gb_exit(void)
{
gb_tty_exit();
+ gb_gbuf_exit();
+ gb_ap_exit();
bus_unregister(&greybus_bus_type);
gb_debugfs_cleanup();
}
#include <linux/kref.h>
#include <linux/device.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include "greybus.h"
return 0;
}
-void gb_deregister_cport_handler(int cport)
+void gb_deregister_cport_complete(int cport)
{
cport_handler[cport].handler = NULL;
}
+struct cport_msg {
+ struct gbuf *gbuf;
+ struct work_struct event;
+};
+
+static struct workqueue_struct *cport_workqueue;
+
+static void cport_process_event(struct work_struct *work)
+{
+ struct cport_msg *cm;
+ struct gbuf *gbuf;
+
+ cm = container_of(work, struct cport_msg, event);
+
+ gbuf = cm->gbuf;
+
+ /* call the gbuf handler */
+ gbuf->complete(gbuf);
+
+ /* free all the memory */
+ kfree(gbuf->transfer_buffer);
+ kfree(gbuf);
+ kfree(cm);
+}
+
void greybus_cport_in_data(struct greybus_host_device *hd, int cport, u8 *data,
size_t length)
{
struct gb_cport_handler *ch;
struct gbuf *gbuf;
+ struct cport_msg *cm;
/* first check to see if we have a cport handler for this cport */
ch = &cport_handler[cport];
pr_err("can't allocate gbuf???\n");
return;
}
- /* Set the data pointers */
+ gbuf->hdpriv = hd;
+
+ /*
+ * FIXME:
+ * Very dumb copy data method for now, if this is slow (odds are it will
+ * be, we should move to a model where the hd "owns" all buffers, but we
+ * want something up and working first for now.
+ */
+ gbuf->transfer_buffer = kmalloc(length, GFP_ATOMIC);
+ if (!gbuf->transfer_buffer) {
+ kfree(gbuf);
+ return;
+ }
+ memcpy(gbuf->transfer_buffer, data, length);
+ gbuf->transfer_buffer_length = length;
- // FIXME - implement...
+ /* Again with the slow allocate... */
+ cm = kmalloc(sizeof(*cm), GFP_ATOMIC);
+
+ /* Queue up the cport message to be handled in user context */
+ cm->gbuf = gbuf;
+ INIT_WORK(&cm->event, cport_process_event);
+ queue_work(cport_workqueue, &cm->event);
}
EXPORT_SYMBOL_GPL(greybus_cport_in_data);
-int greybus_gbuf_init(void)
+int gb_gbuf_init(void)
{
+ cport_workqueue = alloc_workqueue("greybus_gbuf", 0, 1);
+ if (!cport_workqueue)
+ return -ENOMEM;
+
return 0;
}
-void greybus_gbuf_exit(void)
+void gb_gbuf_exit(void)
{
+ destroy_workqueue(cport_workqueue);
}
/* Internal functions to gb module, move to internal .h file eventually. */
int gb_new_ap_msg(u8 *data, int length, struct greybus_host_device *hd);
-int gb_thread_init(void);
-void gb_thread_destroy(void);
+int gb_ap_init(void);
+void gb_ap_exit(void);
int gb_debugfs_init(void);
void gb_debugfs_cleanup(void);
+int gb_gbuf_init(void);
+void gb_gbuf_exit(void);
int gb_register_cport_complete(struct greybus_device *gdev,
gbuf_complete_t handler, int cport,