aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/mon/mon_main.c
diff options
pre { line-height: 125%; margin: 0; } td.linenos pre { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; } span.linenos { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; } td.linenos pre.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; } span.linenos.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; } .highlight .hll { background-color: #ffffcc } .highlight { background: #ffffff; } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
// dear imgui: Renderer for Metal
// This needs to be used along with a Platform Binding (e.g. OSX)

// Implemented features:
//  [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.

// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui

@class MTLRenderPassDescriptor;
@protocol MTLDevice, MTLCommandBuffer, MTLRenderCommandEncoder;

IMGUI_IMPL_API bool ImGui_ImplMetal_Init(id<MTLDevice> device);
IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor *renderPassDescriptor);
IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
                                                   id<MTLCommandBuffer> commandBuffer,
                                                   id<MTLRenderCommandEncoder> commandEncoder);

// Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateFontsTexture(id<MTLDevice> device);
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyFontsTexture();
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device);
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();
context:
>+ mon_bus_complete(mbus, urb, status);
+ mon_bus_complete(&mon_bus0, urb, status);
+}
+
+/* int (*unlink_urb) (struct urb *urb, int status); */
+
+/*
+ * Stop monitoring.
+ */
+static void mon_stop(struct mon_bus *mbus)
+{
+ struct usb_bus *ubus;
+ struct list_head *p;
+
+ if (mbus == &mon_bus0) {
+ list_for_each (p, &mon_buses) {
+ mbus = list_entry(p, struct mon_bus, bus_link);
+ /*
+ * We do not change nreaders here, so rely on mon_lock.
+ */
+ if (mbus->nreaders == 0 && (ubus = mbus->u_bus) != NULL)
+ ubus->monitored = 0;
+ }
+ } else {
+ /*
+ * A stop can be called for a dissolved mon_bus in case of
+ * a reader staying across an rmmod foo_hcd, so test ->u_bus.
+ */
+ if (mon_bus0.nreaders == 0 && (ubus = mbus->u_bus) != NULL) {
+ ubus->monitored = 0;
+ mb();
+ }
+ }
+}
+
+/*
+ * Add a USB bus (usually by a modprobe foo-hcd)
+ *
+ * This does not return an error code because the core cannot care less
+ * if monitoring is not established.
+ */
+static void mon_bus_add(struct usb_bus *ubus)
+{
+ mon_bus_init(ubus);
+ mutex_lock(&mon_lock);
+ if (mon_bus0.nreaders != 0)
+ ubus->monitored = 1;
+ mutex_unlock(&mon_lock);
+}
+
+/*
+ * Remove a USB bus (either from rmmod foo-hcd or from a hot-remove event).
+ */
+static void mon_bus_remove(struct usb_bus *ubus)
+{
+ struct mon_bus *mbus = ubus->mon_bus;
+
+ mutex_lock(&mon_lock);
+ list_del(&mbus->bus_link);
+ if (mbus->text_inited)
+ mon_text_del(mbus);
+ if (mbus->bin_inited)
+ mon_bin_del(mbus);
+
+ mon_dissolve(mbus, ubus);
+ kref_put(&mbus->ref, mon_bus_drop);
+ mutex_unlock(&mon_lock);
+}
+
+static int mon_notify(struct notifier_block *self, unsigned long action,
+ void *dev)
+{
+ switch (action) {
+ case USB_BUS_ADD:
+ mon_bus_add(dev);
+ break;
+ case USB_BUS_REMOVE:
+ mon_bus_remove(dev);
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block mon_nb = {
+ .notifier_call = mon_notify,
+};
+
+/*
+ * Ops
+ */
+static struct usb_mon_operations mon_ops_0 = {
+ .urb_submit = mon_submit,
+ .urb_submit_error = mon_submit_error,
+ .urb_complete = mon_complete,
+};
+
+/*
+ * Tear usb_bus and mon_bus apart.
+ */
+static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus)
+{
+
+ if (ubus->monitored) {
+ ubus->monitored = 0;
+ mb();
+ }
+
+ ubus->mon_bus = NULL;
+ mbus->u_bus = NULL;
+ mb();
+
+ /* We want synchronize_irq() here, but that needs an argument. */
+}
+
+/*
+ */
+static void mon_bus_drop(struct kref *r)
+{
+ struct mon_bus *mbus = container_of(r, struct mon_bus, ref);
+ kfree(mbus);
+}
+
+/*
+ * Initialize a bus for us:
+ * - allocate mon_bus
+ * - refcount USB bus struct
+ * - link
+ */
+static void mon_bus_init(struct usb_bus *ubus)
+{
+ struct mon_bus *mbus;
+
+ if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
+ goto err_alloc;
+ kref_init(&mbus->ref);
+ spin_lock_init(&mbus->lock);
+ INIT_LIST_HEAD(&mbus->r_list);
+
+ /*
+ * We don't need to take a reference to ubus, because we receive
+ * a notification if the bus is about to be removed.
+ */
+ mbus->u_bus = ubus;
+ ubus->mon_bus = mbus;
+
+ mbus->text_inited = mon_text_add(mbus, ubus);
+ mbus->bin_inited = mon_bin_add(mbus, ubus);
+
+ mutex_lock(&mon_lock);
+ list_add_tail(&mbus->bus_link, &mon_buses);
+ mutex_unlock(&mon_lock);
+ return;
+
+err_alloc:
+ return;
+}
+
+static void mon_bus0_init(void)
+{
+ struct mon_bus *mbus = &mon_bus0;
+
+ kref_init(&mbus->ref);
+ spin_lock_init(&mbus->lock);
+ INIT_LIST_HEAD(&mbus->r_list);
+
+ mbus->text_inited = mon_text_add(mbus, NULL);
+ mbus->bin_inited = mon_bin_add(mbus, NULL);
+}
+
+/*
+ * Search a USB bus by number. Notice that USB bus numbers start from one,
+ * which we may later use to identify "all" with zero.
+ *
+ * This function must be called with mon_lock held.
+ *
+ * This is obviously inefficient and may be revised in the future.
+ */
+struct mon_bus *mon_bus_lookup(unsigned int num)
+{
+ struct list_head *p;
+ struct mon_bus *mbus;
+
+ if (num == 0) {
+ return &mon_bus0;
+ }
+ list_for_each (p, &mon_buses) {
+ mbus = list_entry(p, struct mon_bus, bus_link);
+ if (mbus->u_bus->busnum == num) {
+ return mbus;
+ }
+ }
+ return NULL;
+}
+
+static int __init mon_init(void)
+{
+ struct usb_bus *ubus;
+ int rc;
+
+ if ((rc = mon_text_init()) != 0)
+ goto err_text;
+ if ((rc = mon_bin_init()) != 0)
+ goto err_bin;
+
+ mon_bus0_init();
+
+ if (usb_mon_register(&mon_ops_0) != 0) {
+ printk(KERN_NOTICE TAG ": unable to register with the core\n");
+ rc = -ENODEV;
+ goto err_reg;
+ }
+ // MOD_INC_USE_COUNT(which_module?);
+
+ mutex_lock(&usb_bus_list_lock);
+ list_for_each_entry (ubus, &usb_bus_list, bus_list) {
+ mon_bus_init(ubus);
+ }
+ usb_register_notify(&mon_nb);
+ mutex_unlock(&usb_bus_list_lock);
+ return 0;
+
+err_reg:
+ mon_bin_exit();
+err_bin:
+ mon_text_exit();
+err_text:
+ return rc;
+}
+
+static void __exit mon_exit(void)
+{
+ struct mon_bus *mbus;
+ struct list_head *p;
+
+ usb_unregister_notify(&mon_nb);
+ usb_mon_deregister();
+
+ mutex_lock(&mon_lock);
+
+ while (!list_empty(&mon_buses)) {
+ p = mon_buses.next;
+ mbus = list_entry(p, struct mon_bus, bus_link);
+ list_del(p);
+
+ if (mbus->text_inited)
+ mon_text_del(mbus);
+ if (mbus->bin_inited)
+ mon_bin_del(mbus);
+
+ /*
+ * This never happens, because the open/close paths in
+ * file level maintain module use counters and so rmmod fails
+ * before reaching here. However, better be safe...
+ */
+ if (mbus->nreaders) {
+ printk(KERN_ERR TAG
+ ": Outstanding opens (%d) on usb%d, leaking...\n",
+ mbus->nreaders, mbus->u_bus->busnum);
+ atomic_set(&mbus->ref.refcount, 2); /* Force leak */
+ }
+
+ mon_dissolve(mbus, mbus->u_bus);
+ kref_put(&mbus->ref, mon_bus_drop);
+ }
+
+ mbus = &mon_bus0;
+ if (mbus->text_inited)
+ mon_text_del(mbus);
+ if (mbus->bin_inited)
+ mon_bin_del(mbus);
+
+ mutex_unlock(&mon_lock);
+
+ mon_text_exit();
+ mon_bin_exit();
+}
+
+module_init(mon_init);
+module_exit(mon_exit);
+
+MODULE_LICENSE("GPL");