drivers/comedi/comedi_buf.c

Source file repositories/reference/linux-study-clean/drivers/comedi/comedi_buf.c

File Facts

System
Linux kernel
Corpus path
drivers/comedi/comedi_buf.c
Extension
.c
Size
19796 bytes
Lines
739
Domain
Driver Families
Bucket
drivers/comedi
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

if (bm->dma_dir != DMA_NONE) {
			for (i = 0; i < bm->n_pages; i++) {
				buf = &bm->page_list[i];
				dma_free_coherent(bm->dma_hw_dev, PAGE_SIZE,
						  buf->virt_addr,
						  buf->dma_addr);
			}
		} else {
			for (i = 0; i < bm->n_pages; i++) {
				buf = &bm->page_list[i];
				ClearPageReserved(virt_to_page(buf->virt_addr));
				free_page((unsigned long)buf->virt_addr);
			}
		}
		vfree(bm->page_list);
	}
	if (bm->dma_dir != DMA_NONE)
		put_device(bm->dma_hw_dev);
	kfree(bm);
}

static void __comedi_buf_free(struct comedi_device *dev,
			      struct comedi_subdevice *s)
{
	struct comedi_async *async = s->async;
	struct comedi_buf_map *bm;
	unsigned long flags;

	async->prealloc_bufsz = 0;
	spin_lock_irqsave(&s->spin_lock, flags);
	bm = async->buf_map;
	async->buf_map = NULL;
	spin_unlock_irqrestore(&s->spin_lock, flags);
	comedi_buf_map_put(bm);
}

static struct comedi_buf_map *
comedi_buf_map_alloc(struct comedi_device *dev, enum dma_data_direction dma_dir,
		     unsigned int n_pages)
{
	struct comedi_buf_map *bm;
	struct comedi_buf_page *buf;
	unsigned int i;

	bm = kzalloc_obj(*bm);
	if (!bm)
		return NULL;

	kref_init(&bm->refcount);
	bm->dma_dir = dma_dir;
	if (bm->dma_dir != DMA_NONE) {
		/* Need ref to hardware device to free buffer later. */
		bm->dma_hw_dev = get_device(dev->hw_dev);
	}

	bm->page_list = vzalloc(sizeof(*buf) * n_pages);
	if (!bm->page_list)
		goto err;

	if (bm->dma_dir != DMA_NONE) {
		for (i = 0; i < n_pages; i++) {
			buf = &bm->page_list[i];
			buf->virt_addr =
			    dma_alloc_coherent(bm->dma_hw_dev, PAGE_SIZE,
					       &buf->dma_addr, GFP_KERNEL);
			if (!buf->virt_addr)
				break;
		}
	} else {
		for (i = 0; i < n_pages; i++) {
			buf = &bm->page_list[i];
			buf->virt_addr = (void *)get_zeroed_page(GFP_KERNEL);
			if (!buf->virt_addr)
				break;

			SetPageReserved(virt_to_page(buf->virt_addr));
		}
	}
	bm->n_pages = i;
	if (i < n_pages)
		goto err;

	return bm;

err:
	comedi_buf_map_put(bm);
	return NULL;
}

static void __comedi_buf_alloc(struct comedi_device *dev,

Annotation

Implementation Notes