drivers/uio/uio_fsl_elbc_gpcm.c

Source file repositories/reference/linux-study-clean/drivers/uio/uio_fsl_elbc_gpcm.c

File Facts

System
Linux kernel
Corpus path
drivers/uio/uio_fsl_elbc_gpcm.c
Extension
.c
Size
12255 bytes
Lines
470
Domain
Driver Families
Bucket
drivers/uio
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

struct fsl_elbc_gpcm {
	struct device *dev;
	struct fsl_lbc_regs __iomem *lbc;
	u32 bank;
	const char *name;

	void (*init)(struct uio_info *info);
	void (*shutdown)(struct uio_info *info, bool init_err);
	irqreturn_t (*irq_handler)(int irq, struct uio_info *info);
};

static ssize_t reg_show(struct device *dev, struct device_attribute *attr,
			char *buf);
static ssize_t reg_store(struct device *dev, struct device_attribute *attr,
			 const char *buf, size_t count);

static DEVICE_ATTR(reg_br, 0664, reg_show, reg_store);
static DEVICE_ATTR(reg_or, 0664, reg_show, reg_store);

static struct attribute *uio_fsl_elbc_gpcm_attrs[] = {
	&dev_attr_reg_br.attr,
	&dev_attr_reg_or.attr,
	NULL,
};
ATTRIBUTE_GROUPS(uio_fsl_elbc_gpcm);

static ssize_t reg_show(struct device *dev, struct device_attribute *attr,
			char *buf)
{
	struct uio_info *info = dev_get_drvdata(dev);
	struct fsl_elbc_gpcm *priv = info->priv;
	struct fsl_lbc_bank *bank = &priv->lbc->bank[priv->bank];

	if (attr == &dev_attr_reg_br) {
		return scnprintf(buf, PAGE_SIZE, "0x%08x\n",
				 in_be32(&bank->br));

	} else if (attr == &dev_attr_reg_or) {
		return scnprintf(buf, PAGE_SIZE, "0x%08x\n",
				 in_be32(&bank->or));
	}

	return 0;
}

static ssize_t reg_store(struct device *dev, struct device_attribute *attr,
			 const char *buf, size_t count)
{
	struct uio_info *info = dev_get_drvdata(dev);
	struct fsl_elbc_gpcm *priv = info->priv;
	struct fsl_lbc_bank *bank = &priv->lbc->bank[priv->bank];
	unsigned long val;
	u32 reg_br_cur;
	u32 reg_or_cur;
	u32 reg_new;

	/* parse use input */
	if (kstrtoul(buf, 0, &val) != 0)
		return -EINVAL;
	reg_new = (u32)val;

	/* read current values */
	reg_br_cur = in_be32(&bank->br);
	reg_or_cur = in_be32(&bank->or);

	if (attr == &dev_attr_reg_br) {
		/* not allowed to change effective base address */
		if ((reg_br_cur & reg_or_cur & BR_BA) !=
		    (reg_new & reg_or_cur & BR_BA)) {
			return -EINVAL;
		}

		/* not allowed to change mode */
		if ((reg_new & BR_MSEL) != BR_MS_GPCM)
			return -EINVAL;

		/* write new value (force valid) */
		out_be32(&bank->br, reg_new | BR_V);

	} else if (attr == &dev_attr_reg_or) {
		/* not allowed to change access mask */
		if ((reg_or_cur & OR_GPCM_AM) != (reg_new & OR_GPCM_AM))
			return -EINVAL;

		/* write new value */
		out_be32(&bank->or, reg_new);

	} else {
		return -EINVAL;
	}

Annotation

Implementation Notes