drivers/base/firmware_loader/sysfs.c

Source file repositories/reference/linux-study-clean/drivers/base/firmware_loader/sysfs.c

File Facts

System
Linux kernel
Corpus path
drivers/base/firmware_loader/sysfs.c
Extension
.c
Size
10068 bytes
Lines
426
Domain
Driver Families
Bucket
drivers/base
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 (fw_state_is_loading(fw_priv)) {
			int rc;

			/*
			 * Several loading requests may be pending on
			 * one same firmware buf, so let all requests
			 * see the mapped 'buf->data' once the loading
			 * is completed.
			 */
			rc = fw_map_paged_buf(fw_priv);
			if (rc)
				dev_err(dev, "%s: map pages failed\n",
					__func__);
			else
				rc = security_kernel_post_load_data(fw_priv->data,
								    fw_priv->size,
								    LOADING_FIRMWARE,
								    "blob");

			/*
			 * Same logic as fw_load_abort, only the DONE bit
			 * is ignored and we set ABORT only on failure.
			 */
			if (rc) {
				fw_state_aborted(fw_priv);
				written = rc;
			} else {
				fw_state_done(fw_priv);

				/*
				 * If this is a user-initiated firmware upload
				 * then start the upload in a worker thread now.
				 */
				rc = fw_upload_start(fw_sysfs);
				if (rc)
					written = rc;
			}
			break;
		}
		fallthrough;
	default:
		dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading);
		fallthrough;
	case -1:
		fw_load_abort(fw_sysfs);
		if (fw_sysfs->fw_upload_priv)
			fw_state_init(fw_sysfs->fw_priv);

		break;
	}
out:
	mutex_unlock(&fw_lock);
	return written;
}

DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);

static void firmware_rw_data(struct fw_priv *fw_priv, char *buffer,
			     loff_t offset, size_t count, bool read)
{
	if (read)
		memcpy(buffer, fw_priv->data + offset, count);
	else
		memcpy(fw_priv->data + offset, buffer, count);
}

static void firmware_rw(struct fw_priv *fw_priv, char *buffer,
			loff_t offset, size_t count, bool read)
{
	while (count) {
		int page_nr = offset >> PAGE_SHIFT;
		int page_ofs = offset & (PAGE_SIZE - 1);
		int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);

		if (read)
			memcpy_from_page(buffer, fw_priv->pages[page_nr],
					 page_ofs, page_cnt);
		else
			memcpy_to_page(fw_priv->pages[page_nr], page_ofs,
				       buffer, page_cnt);

		buffer += page_cnt;
		offset += page_cnt;
		count -= page_cnt;
	}
}

static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
				  const struct bin_attribute *bin_attr,
				  char *buffer, loff_t offset, size_t count)

Annotation

Implementation Notes