drivers/staging/greybus/raw.c

Source file repositories/reference/linux-study-clean/drivers/staging/greybus/raw.c

File Facts

System
Linux kernel
Corpus path
drivers/staging/greybus/raw.c
Extension
.c
Size
8877 bytes
Lines
400
Domain
Driver Families
Bucket
drivers/staging
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static const struct file_operations raw_fops;
static DEFINE_IDA(minors);

/* Number of minor devices this driver supports */
#define NUM_MINORS	256

/* Maximum size of any one send data buffer we support */
#define MAX_PACKET_SIZE	(PAGE_SIZE * 2)

/*
 * Maximum size of the data in the receive buffer we allow before we start to
 * drop messages on the floor
 */
#define MAX_DATA_SIZE	(MAX_PACKET_SIZE * 8)

/*
 * Add the raw data message to the list of received messages.
 */
static int receive_data(struct gb_raw *raw, u32 len, u8 *data)
{
	struct raw_data *raw_data;
	struct device *dev = &raw->connection->bundle->dev;
	int retval = 0;

	if (len > MAX_PACKET_SIZE) {
		dev_err(dev, "Too big of a data packet, rejected\n");
		return -EINVAL;
	}

	mutex_lock(&raw->list_lock);
	if ((raw->list_data + len) > MAX_DATA_SIZE) {
		dev_err(dev, "Too much data in receive buffer, now dropping packets\n");
		retval = -EINVAL;
		goto exit;
	}

	raw_data = kmalloc_flex(*raw_data, data, len);
	if (!raw_data) {
		retval = -ENOMEM;
		goto exit;
	}

	raw->list_data += len;
	raw_data->len = len;
	memcpy(&raw_data->data[0], data, len);

	list_add_tail(&raw_data->entry, &raw->list);
exit:
	mutex_unlock(&raw->list_lock);
	return retval;
}

static int gb_raw_request_handler(struct gb_operation *op)
{
	struct gb_connection *connection = op->connection;
	struct device *dev = &connection->bundle->dev;
	struct gb_raw *raw = greybus_get_drvdata(connection->bundle);
	struct gb_raw_send_request *receive;
	u32 len;

	if (op->type != GB_RAW_TYPE_SEND) {
		dev_err(dev, "unknown request type 0x%02x\n", op->type);
		return -EINVAL;
	}

	/* Verify size of payload */
	if (op->request->payload_size < sizeof(*receive)) {
		dev_err(dev, "raw receive request too small (%zu < %zu)\n",
			op->request->payload_size, sizeof(*receive));
		return -EINVAL;
	}
	receive = op->request->payload;
	len = le32_to_cpu(receive->len);
	if (len != (int)(op->request->payload_size - sizeof(__le32))) {
		dev_err(dev, "raw receive request wrong size %d vs %d\n", len,
			(int)(op->request->payload_size - sizeof(__le32)));
		return -EINVAL;
	}
	if (len == 0) {
		dev_err(dev, "raw receive request of 0 bytes?\n");
		return -EINVAL;
	}

	return receive_data(raw, len, receive->data);
}

static int gb_raw_send(struct gb_raw *raw, u32 len, const char __user *data)
{
	struct gb_connection *connection = raw->connection;
	struct gb_raw_send_request *request;

Annotation

Implementation Notes