drivers/input/joystick/psxpad-spi.c

Source file repositories/reference/linux-study-clean/drivers/input/joystick/psxpad-spi.c

File Facts

System
Linux kernel
Corpus path
drivers/input/joystick/psxpad-spi.c
Extension
.c
Size
11425 bytes
Lines
413
Domain
Driver Families
Bucket
drivers/input
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 psxpad {
	struct spi_device *spi;
	struct input_dev *idev;
	char phys[0x20];
	bool motor1enable;
	bool motor2enable;
	u8 motor1level;
	u8 motor2level;
	u8 sendbuf[0x20] ____cacheline_aligned;
	u8 response[sizeof(PSX_CMD_POLL)] ____cacheline_aligned;
};

static int psxpad_command(struct psxpad *pad, const u8 sendcmdlen)
{
	struct spi_transfer xfers = {
		.tx_buf		= pad->sendbuf,
		.rx_buf		= pad->response,
		.len		= sendcmdlen,
	};
	int err;

	err = spi_sync_transfer(pad->spi, &xfers, 1);
	if (err) {
		dev_err(&pad->spi->dev,
			"%s: failed to SPI xfers mode: %d\n",
			__func__, err);
		return err;
	}

	return 0;
}

#ifdef CONFIG_JOYSTICK_PSXPAD_SPI_FF
static void psxpad_control_motor(struct psxpad *pad,
				 bool motor1enable, bool motor2enable)
{
	int err;

	pad->motor1enable = motor1enable;
	pad->motor2enable = motor2enable;

	memcpy(pad->sendbuf, PSX_CMD_ENTER_CFG, sizeof(PSX_CMD_ENTER_CFG));
	err = psxpad_command(pad, sizeof(PSX_CMD_ENTER_CFG));
	if (err) {
		dev_err(&pad->spi->dev,
			"%s: failed to enter config mode: %d\n",
			__func__, err);
		return;
	}

	memcpy(pad->sendbuf, PSX_CMD_ENABLE_MOTOR,
	       sizeof(PSX_CMD_ENABLE_MOTOR));
	pad->sendbuf[3] = pad->motor1enable ? 0x00 : 0xFF;
	pad->sendbuf[4] = pad->motor2enable ? 0x80 : 0xFF;
	err = psxpad_command(pad, sizeof(PSX_CMD_ENABLE_MOTOR));
	if (err) {
		dev_err(&pad->spi->dev,
			"%s: failed to enable motor mode: %d\n",
			__func__, err);
		return;
	}

	memcpy(pad->sendbuf, PSX_CMD_EXIT_CFG, sizeof(PSX_CMD_EXIT_CFG));
	err = psxpad_command(pad, sizeof(PSX_CMD_EXIT_CFG));
	if (err) {
		dev_err(&pad->spi->dev,
			"%s: failed to exit config mode: %d\n",
			__func__, err);
		return;
	}
}

static void psxpad_set_motor_level(struct psxpad *pad,
				   u8 motor1level, u8 motor2level)
{
	pad->motor1level = motor1level ? 0xFF : 0x00;
	pad->motor2level = REVERSE_BIT(motor2level);
}

static int psxpad_spi_play_effect(struct input_dev *idev,
				  void *data, struct ff_effect *effect)
{
	struct psxpad *pad = input_get_drvdata(idev);

	switch (effect->type) {
	case FF_RUMBLE:
		psxpad_set_motor_level(pad,
			(effect->u.rumble.weak_magnitude >> 8) & 0xFFU,
			(effect->u.rumble.strong_magnitude >> 8) & 0xFFU);
		break;

Annotation

Implementation Notes