drivers/usb/musb/musb_core.c

Source file repositories/reference/linux-study-clean/drivers/usb/musb/musb_core.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/musb/musb_core.c
Extension
.c
Size
80247 bytes
Lines
2956
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct musb_pending_work {
	int (*callback)(struct musb *musb, void *data);
	void *data;
	struct list_head node;
};

#ifdef CONFIG_PM
/*
 * Called from musb_runtime_resume(), musb_resume(), and
 * musb_queue_resume_work(). Callers must take musb->lock.
 */
static int musb_run_resume_work(struct musb *musb)
{
	struct musb_pending_work *w, *_w;
	unsigned long flags;
	int error = 0;

	spin_lock_irqsave(&musb->list_lock, flags);
	list_for_each_entry_safe(w, _w, &musb->pending_list, node) {
		if (w->callback) {
			error = w->callback(musb, w->data);
			if (error < 0) {
				dev_err(musb->controller,
					"resume callback %p failed: %i\n",
					w->callback, error);
			}
		}
		list_del(&w->node);
		devm_kfree(musb->controller, w);
	}
	spin_unlock_irqrestore(&musb->list_lock, flags);

	return error;
}
#endif

/*
 * Called to run work if device is active or else queue the work to happen
 * on resume. Caller must take musb->lock and must hold an RPM reference.
 *
 * Note that we cowardly refuse queuing work after musb PM runtime
 * resume is done calling musb_run_resume_work() and return -EINPROGRESS
 * instead.
 */
int musb_queue_resume_work(struct musb *musb,
			   int (*callback)(struct musb *musb, void *data),
			   void *data)
{
	struct musb_pending_work *w;
	unsigned long flags;
	bool is_suspended;
	int error;

	if (WARN_ON(!callback))
		return -EINVAL;

	spin_lock_irqsave(&musb->list_lock, flags);
	is_suspended = musb->is_runtime_suspended;

	if (is_suspended) {
		w = devm_kzalloc(musb->controller, sizeof(*w), GFP_ATOMIC);
		if (!w) {
			error = -ENOMEM;
			goto out_unlock;
		}

		w->callback = callback;
		w->data = data;

		list_add_tail(&w->node, &musb->pending_list);
		error = 0;
	}

out_unlock:
	spin_unlock_irqrestore(&musb->list_lock, flags);

	if (!is_suspended)
		error = callback(musb, data);

	return error;
}
EXPORT_SYMBOL_GPL(musb_queue_resume_work);

static void musb_deassert_reset(struct work_struct *work)
{
	struct musb *musb;
	unsigned long flags;

	musb = container_of(work, struct musb, deassert_reset_work.work);

Annotation

Implementation Notes