cregit-Linux how code gets into the kernel

Release 4.7 drivers/usb/mon/mon_main.c

Directory: drivers/usb/mon
/*
 * The USB Monitor, inspired by Dave Harding's USBMon.
 *
 * mon_main.c: Main file, module initiation and exit, registrations, etc.
 *
 * Copyright (C) 2005 Pete Zaitcev (zaitcev@redhat.com)
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/slab.h>
#include <linux/notifier.h>
#include <linux/mutex.h>

#include "usb_mon.h"


static void mon_stop(struct mon_bus *mbus);
static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
static void mon_bus_drop(struct kref *r);
static void mon_bus_init(struct usb_bus *ubus);


DEFINE_MUTEX(mon_lock);


struct mon_bus mon_bus0;		
/* Pseudo bus meaning "all buses" */
static LIST_HEAD(mon_buses);		/* All buses we know: struct mon_bus */

/*
 * Link a reader into the bus.
 *
 * This must be called with mon_lock taken because of mbus->ref.
 */

void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r) { unsigned long flags; struct list_head *p; spin_lock_irqsave(&mbus->lock, flags); if (mbus->nreaders == 0) { if (mbus == &mon_bus0) { list_for_each (p, &mon_buses) { struct mon_bus *m1; m1 = list_entry(p, struct mon_bus, bus_link); m1->u_bus->monitored = 1; } } else { mbus->u_bus->monitored = 1; } } mbus->nreaders++; list_add_tail(&r->r_link, &mbus->r_list); spin_unlock_irqrestore(&mbus->lock, flags); kref_get(&mbus->ref); }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev133100.00%2100.00%
Total133100.00%2100.00%

/* * Unlink reader from the bus. * * This is called with mon_lock taken, so we can decrement mbus->ref. */
void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r) { unsigned long flags; spin_lock_irqsave(&mbus->lock, flags); list_del(&r->r_link); --mbus->nreaders; if (mbus->nreaders == 0) mon_stop(mbus); spin_unlock_irqrestore(&mbus->lock, flags); kref_put(&mbus->ref, mon_bus_drop); }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev75100.00%1100.00%
Total75100.00%1100.00%

/* */
static void mon_bus_submit(struct mon_bus *mbus, struct urb *urb) { unsigned long flags; struct list_head *pos; struct mon_reader *r; spin_lock_irqsave(&mbus->lock, flags); mbus->cnt_events++; list_for_each (pos, &mbus->r_list) { r = list_entry(pos, struct mon_reader, r_link); r->rnf_submit(r->r_data, urb); } spin_unlock_irqrestore(&mbus->lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev86100.00%3100.00%
Total86100.00%3100.00%


static void mon_submit(struct usb_bus *ubus, struct urb *urb) { struct mon_bus *mbus; mbus = ubus->mon_bus; if (mbus != NULL) mon_bus_submit(mbus, urb); mon_bus_submit(&mon_bus0, urb); }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev4491.67%266.67%
greg kroah-hartmangreg kroah-hartman48.33%133.33%
Total48100.00%3100.00%

/* */
static void mon_bus_submit_error(struct mon_bus *mbus, struct urb *urb, int error) { unsigned long flags; struct list_head *pos; struct mon_reader *r; spin_lock_irqsave(&mbus->lock, flags); mbus->cnt_events++; list_for_each (pos, &mbus->r_list) { r = list_entry(pos, struct mon_reader, r_link); r->rnf_error(r->r_data, urb, error); } spin_unlock_irqrestore(&mbus->lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev91100.00%3100.00%
Total91100.00%3100.00%


static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) { struct mon_bus *mbus; mbus = ubus->mon_bus; if (mbus != NULL) mon_bus_submit_error(mbus, urb, error); mon_bus_submit_error(&mon_bus0, urb, error); }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev5192.73%150.00%
greg kroah-hartmangreg kroah-hartman47.27%150.00%
Total55100.00%2100.00%

/* */
static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb, int status) { unsigned long flags; struct list_head *pos; struct mon_reader *r; spin_lock_irqsave(&mbus->lock, flags); mbus->cnt_events++; list_for_each (pos, &mbus->r_list) { r = list_entry(pos, struct mon_reader, r_link); r->rnf_complete(r->r_data, urb, status); } spin_unlock_irqrestore(&mbus->lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev8694.51%375.00%
alan sternalan stern55.49%125.00%
Total91100.00%4100.00%


static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status) { struct mon_bus *mbus; mbus = ubus->mon_bus; if (mbus != NULL) mon_bus_complete(mbus, urb, status); mon_bus_complete(&mon_bus0, urb, status); }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev4480.00%466.67%
alan sternalan stern712.73%116.67%
greg kroah-hartmangreg kroah-hartman47.27%116.67%
Total55100.00%6100.00%

/* 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(); } } }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev108100.00%2100.00%
Total108100.00%2100.00%

/* * 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); }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev42100.00%2100.00%
Total42100.00%2100.00%

/* * 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); }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev7797.47%375.00%
arjan van de venarjan van de ven22.53%125.00%
Total79100.00%4100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
greg kroah-hartmangreg kroah-hartman45100.00%1100.00%
Total45100.00%1100.00%

static struct notifier_block mon_nb = { .notifier_call = mon_notify, }; /* * Ops */ static const 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. */ }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev49100.00%2100.00%
Total49100.00%2100.00%

/* */
static void mon_bus_drop(struct kref *r) { struct mon_bus *mbus = container_of(r, struct mon_bus, ref); kfree(mbus); }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev31100.00%1100.00%
Total31100.00%1100.00%

/* * 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; mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL); if (mbus == 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; }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev11491.94%444.44%
greg kroah-hartmangreg kroah-hartman43.23%111.11%
alan sternalan stern32.42%222.22%
arjan van de venarjan van de ven21.61%111.11%
eric sesterhenneric sesterhenn10.81%111.11%
Total124100.00%9100.00%


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); }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev62100.00%2100.00%
Total62100.00%2100.00%

/* * 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; }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev71100.00%3100.00%
Total71100.00%3100.00%


static int __init mon_init(void) { struct usb_bus *ubus; int rc, id; 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_idr_lock); idr_for_each_entry(&usb_bus_idr, ubus, id) mon_bus_init(ubus); usb_register_notify(&mon_nb); mutex_unlock(&usb_bus_idr_lock); return 0; err_reg: mon_bin_exit(); err_bin: mon_text_exit(); err_text: return rc; }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev11087.30%342.86%
heiner kallweitheiner kallweit86.35%228.57%
arjan van de venarjan van de ven86.35%228.57%
Total126100.00%7100.00%


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(); }

Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev17295.56%466.67%
greg kroah-hartmangreg kroah-hartman63.33%116.67%
arjan van de venarjan van de ven21.11%116.67%
Total180100.00%6100.00%

module_init(mon_init); module_exit(mon_exit); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
pete zaitcevpete zaitcev157292.36%838.10%
greg kroah-hartmangreg kroah-hartman814.76%29.52%
arjan van de venarjan van de ven171.00%29.52%
alan sternalan stern150.88%314.29%
heiner kallweitheiner kallweit80.47%29.52%
eric lescoueteric lescouet50.29%14.76%
tejun heotejun heo20.12%14.76%
julia lawalljulia lawall10.06%14.76%
eric sesterhenneric sesterhenn10.06%14.76%
Total1702100.00%21100.00%
Directory: drivers/usb/mon
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}