drivers/gpu/drm/udl/udl_main.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/udl/udl_main.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/udl/udl_main.c
Extension
.c
Size
8903 bytes
Lines
387
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source 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

if (!urb) {
			kfree(unode);
			break;
		}
		unode->urb = urb;

		buf = usb_alloc_coherent(udev, size, GFP_KERNEL,
					 &urb->transfer_dma);
		if (!buf) {
			kfree(unode);
			usb_free_urb(urb);
			if (size > PAGE_SIZE) {
				size /= 2;
				udl_free_urb_list(udl);
				goto retry;
			}
			break;
		}

		/* urb->transfer_buffer_length set to actual before submit */
		usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, 1),
				  buf, size, udl_urb_completion, unode);
		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

		list_add_tail(&unode->entry, &udl->urbs.list);

		udl->urbs.count++;
		udl->urbs.available++;
	}

	DRM_DEBUG("allocated %d %d byte urbs\n", udl->urbs.count, (int) size);

	return udl->urbs.count;
}

static struct urb *udl_get_urb_locked(struct udl_device *udl, long timeout)
{
	struct urb_node *unode;

	assert_spin_locked(&udl->urbs.lock);

	/* Wait for an in-flight buffer to complete and get re-queued */
	if (!wait_event_lock_irq_timeout(udl->urbs.sleep,
					 !udl->urbs.count ||
					 !list_empty(&udl->urbs.list),
					 udl->urbs.lock, timeout)) {
		DRM_INFO("wait for urb interrupted: available: %d\n",
			 udl->urbs.available);
		return NULL;
	}

	if (!udl->urbs.count)
		return NULL;

	unode = list_first_entry(&udl->urbs.list, struct urb_node, entry);
	list_del_init(&unode->entry);
	udl->urbs.available--;

	return unode->urb;
}

struct urb *udl_get_urb(struct udl_device *udl)
{
	struct urb *urb;

	spin_lock_irq(&udl->urbs.lock);
	urb = udl_get_urb_locked(udl, HZ * 2);
	spin_unlock_irq(&udl->urbs.lock);
	return urb;
}

int udl_submit_urb(struct udl_device *udl, struct urb *urb, size_t len)
{
	int ret;

	if (WARN_ON(len > udl->urbs.size)) {
		ret = -EINVAL;
		goto error;
	}
	urb->transfer_buffer_length = len; /* set to actual payload len */
	ret = usb_submit_urb(urb, GFP_ATOMIC);
 error:
	if (ret) {
		udl_urb_completion(urb); /* because no one else will */
		DRM_ERROR("usb_submit_urb error %x\n", ret);
	}
	return ret;
}

/* wait until all pending URBs have been processed */

Annotation

Implementation Notes