Loading drivers/staging/greybus/Makefile +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 Loading drivers/staging/greybus/ap.c 0 → 100644 +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); } drivers/staging/greybus/core.c +11 −3 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -199,7 +200,7 @@ static int __init gb_init(void) { int retval; retval = greybus_debugfs_init(); retval = gb_debugfs_init(); if (retval) return retval; Loading @@ -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(); Loading @@ -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; } Loading @@ -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); Loading drivers/staging/greybus/debugfs.c +2 −2 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -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); } drivers/staging/greybus/es1-ap-usb.c +63 −1 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading
drivers/staging/greybus/Makefile +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 Loading
drivers/staging/greybus/ap.c 0 → 100644 +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); }
drivers/staging/greybus/core.c +11 −3 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -199,7 +200,7 @@ static int __init gb_init(void) { int retval; retval = greybus_debugfs_init(); retval = gb_debugfs_init(); if (retval) return retval; Loading @@ -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(); Loading @@ -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; } Loading @@ -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); Loading
drivers/staging/greybus/debugfs.c +2 −2 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -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); }
drivers/staging/greybus/es1-ap-usb.c +63 −1 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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