drivers/platform/surface/surface_hotplug.c

Source file repositories/reference/linux-study-clean/drivers/platform/surface/surface_hotplug.c

File Facts

System
Linux kernel
Corpus path
drivers/platform/surface/surface_hotplug.c
Extension
.c
Size
8121 bytes
Lines
274
Domain
Driver Families
Bucket
drivers/platform
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 shps_device {
	struct mutex lock[SHPS_NUM_IRQS];  /* Protects update in shps_dsm_notify_irq() */
	struct gpio_desc *gpio[SHPS_NUM_IRQS];
	unsigned int irq[SHPS_NUM_IRQS];
};

#define SHPS_IRQ_NOT_PRESENT		((unsigned int)-1)

static enum shps_dsm_fn shps_dsm_fn_for_irq(enum shps_irq_type type)
{
	return SHPS_DSM_FN_IRQ_BASE_PRESENCE + type;
}

static void shps_dsm_notify_irq(struct platform_device *pdev, enum shps_irq_type type)
{
	struct shps_device *sdev = platform_get_drvdata(pdev);
	acpi_handle handle = ACPI_HANDLE(&pdev->dev);
	union acpi_object *result;
	union acpi_object param;
	int value;

	mutex_lock(&sdev->lock[type]);

	value = gpiod_get_value_cansleep(sdev->gpio[type]);
	if (value < 0) {
		mutex_unlock(&sdev->lock[type]);
		dev_err(&pdev->dev, "failed to get gpio: %d (irq=%d)\n", type, value);
		return;
	}

	dev_dbg(&pdev->dev, "IRQ notification via DSM (irq=%d, value=%d)\n", type, value);

	param.type = ACPI_TYPE_INTEGER;
	param.integer.value = value;

	result = acpi_evaluate_dsm_typed(handle, &shps_dsm_guid, SHPS_DSM_REVISION,
					 shps_dsm_fn_for_irq(type), &param, ACPI_TYPE_BUFFER);
	if (!result) {
		dev_err(&pdev->dev, "IRQ notification via DSM failed (irq=%d, gpio=%d)\n",
			type, value);

	} else if (result->buffer.length != 1 || result->buffer.pointer[0] != 0) {
		dev_err(&pdev->dev,
			"IRQ notification via DSM failed: unexpected result value (irq=%d, gpio=%d)\n",
			type, value);
	}

	mutex_unlock(&sdev->lock[type]);

	ACPI_FREE(result);
}

static irqreturn_t shps_handle_irq(int irq, void *data)
{
	struct platform_device *pdev = data;
	struct shps_device *sdev = platform_get_drvdata(pdev);
	int type;

	/* Figure out which IRQ we're handling. */
	for (type = 0; type < SHPS_NUM_IRQS; type++)
		if (irq == sdev->irq[type])
			break;

	/* We should have found our interrupt, if not: this is a bug. */
	if (WARN(type >= SHPS_NUM_IRQS, "invalid IRQ number: %d\n", irq))
		return IRQ_HANDLED;

	/* Forward interrupt to ACPI via DSM. */
	shps_dsm_notify_irq(pdev, type);
	return IRQ_HANDLED;
}

static int shps_setup_irq(struct platform_device *pdev, enum shps_irq_type type)
{
	unsigned long flags = IRQF_ONESHOT | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
	struct shps_device *sdev = platform_get_drvdata(pdev);
	struct gpio_desc *gpiod;
	acpi_handle handle = ACPI_HANDLE(&pdev->dev);
	const char *irq_name;
	const int dsm = shps_dsm_fn_for_irq(type);
	int status, irq;

	/*
	 * Only set up interrupts that we actually need: The Surface Book 3
	 * does not have a DSM for base presence, so don't set up an interrupt
	 * for that.
	 */
	if (!acpi_check_dsm(handle, &shps_dsm_guid, SHPS_DSM_REVISION, BIT(dsm))) {
		dev_dbg(&pdev->dev, "IRQ notification via DSM not present (irq=%d)\n", type);
		return 0;

Annotation

Implementation Notes