cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

psxpad-spi.c (11238B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * PlayStation 1/2 joypads via SPI interface Driver
      4 *
      5 * Copyright (C) 2017 Tomohiro Yoshidomi <sylph23k@gmail.com>
      6 *
      7 * PlayStation 1/2 joypad's plug (not socket)
      8 *  123 456 789
      9 * (...|...|...)
     10 *
     11 * 1: DAT -> MISO (pullup with 1k owm to 3.3V)
     12 * 2: CMD -> MOSI
     13 * 3: 9V (for motor, if not use N.C.)
     14 * 4: GND
     15 * 5: 3.3V
     16 * 6: Attention -> CS(SS)
     17 * 7: SCK -> SCK
     18 * 8: N.C.
     19 * 9: ACK -> N.C.
     20 */
     21
     22#include <linux/kernel.h>
     23#include <linux/device.h>
     24#include <linux/input.h>
     25#include <linux/module.h>
     26#include <linux/spi/spi.h>
     27#include <linux/types.h>
     28#include <linux/pm.h>
     29#include <linux/pm_runtime.h>
     30
     31#define REVERSE_BIT(x) ((((x) & 0x80) >> 7) | (((x) & 0x40) >> 5) | \
     32	(((x) & 0x20) >> 3) | (((x) & 0x10) >> 1) | (((x) & 0x08) << 1) | \
     33	(((x) & 0x04) << 3) | (((x) & 0x02) << 5) | (((x) & 0x01) << 7))
     34
     35/* PlayStation 1/2 joypad command and response are LSBFIRST. */
     36
     37/*
     38 *	0x01, 0x42, 0x00, 0x00, 0x00,
     39 *	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     40 *	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     41 */
     42static const u8 PSX_CMD_POLL[] = {
     43	0x80, 0x42, 0x00, 0x00, 0x00,
     44	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     45	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     46};
     47/*	0x01, 0x43, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 */
     48static const u8 PSX_CMD_ENTER_CFG[] = {
     49	0x80, 0xC2, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00
     50};
     51/*	0x01, 0x43, 0x00, 0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A */
     52static const u8 PSX_CMD_EXIT_CFG[] = {
     53	0x80, 0xC2, 0x00, 0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A
     54};
     55/*	0x01, 0x4D, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF */
     56static const u8 PSX_CMD_ENABLE_MOTOR[]	= {
     57	0x80, 0xB2, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF
     58};
     59
     60struct psxpad {
     61	struct spi_device *spi;
     62	struct input_dev *idev;
     63	char phys[0x20];
     64	bool motor1enable;
     65	bool motor2enable;
     66	u8 motor1level;
     67	u8 motor2level;
     68	u8 sendbuf[0x20] ____cacheline_aligned;
     69	u8 response[sizeof(PSX_CMD_POLL)] ____cacheline_aligned;
     70};
     71
     72static int psxpad_command(struct psxpad *pad, const u8 sendcmdlen)
     73{
     74	struct spi_transfer xfers = {
     75		.tx_buf		= pad->sendbuf,
     76		.rx_buf		= pad->response,
     77		.len		= sendcmdlen,
     78	};
     79	int err;
     80
     81	err = spi_sync_transfer(pad->spi, &xfers, 1);
     82	if (err) {
     83		dev_err(&pad->spi->dev,
     84			"%s: failed to SPI xfers mode: %d\n",
     85			__func__, err);
     86		return err;
     87	}
     88
     89	return 0;
     90}
     91
     92#ifdef CONFIG_JOYSTICK_PSXPAD_SPI_FF
     93static void psxpad_control_motor(struct psxpad *pad,
     94				 bool motor1enable, bool motor2enable)
     95{
     96	int err;
     97
     98	pad->motor1enable = motor1enable;
     99	pad->motor2enable = motor2enable;
    100
    101	memcpy(pad->sendbuf, PSX_CMD_ENTER_CFG, sizeof(PSX_CMD_ENTER_CFG));
    102	err = psxpad_command(pad, sizeof(PSX_CMD_ENTER_CFG));
    103	if (err) {
    104		dev_err(&pad->spi->dev,
    105			"%s: failed to enter config mode: %d\n",
    106			__func__, err);
    107		return;
    108	}
    109
    110	memcpy(pad->sendbuf, PSX_CMD_ENABLE_MOTOR,
    111	       sizeof(PSX_CMD_ENABLE_MOTOR));
    112	pad->sendbuf[3] = pad->motor1enable ? 0x00 : 0xFF;
    113	pad->sendbuf[4] = pad->motor2enable ? 0x80 : 0xFF;
    114	err = psxpad_command(pad, sizeof(PSX_CMD_ENABLE_MOTOR));
    115	if (err) {
    116		dev_err(&pad->spi->dev,
    117			"%s: failed to enable motor mode: %d\n",
    118			__func__, err);
    119		return;
    120	}
    121
    122	memcpy(pad->sendbuf, PSX_CMD_EXIT_CFG, sizeof(PSX_CMD_EXIT_CFG));
    123	err = psxpad_command(pad, sizeof(PSX_CMD_EXIT_CFG));
    124	if (err) {
    125		dev_err(&pad->spi->dev,
    126			"%s: failed to exit config mode: %d\n",
    127			__func__, err);
    128		return;
    129	}
    130}
    131
    132static void psxpad_set_motor_level(struct psxpad *pad,
    133				   u8 motor1level, u8 motor2level)
    134{
    135	pad->motor1level = motor1level ? 0xFF : 0x00;
    136	pad->motor2level = REVERSE_BIT(motor2level);
    137}
    138
    139static int psxpad_spi_play_effect(struct input_dev *idev,
    140				  void *data, struct ff_effect *effect)
    141{
    142	struct psxpad *pad = input_get_drvdata(idev);
    143
    144	switch (effect->type) {
    145	case FF_RUMBLE:
    146		psxpad_set_motor_level(pad,
    147			(effect->u.rumble.weak_magnitude >> 8) & 0xFFU,
    148			(effect->u.rumble.strong_magnitude >> 8) & 0xFFU);
    149		break;
    150	}
    151
    152	return 0;
    153}
    154
    155static int psxpad_spi_init_ff(struct psxpad *pad)
    156{
    157	int err;
    158
    159	input_set_capability(pad->idev, EV_FF, FF_RUMBLE);
    160
    161	err = input_ff_create_memless(pad->idev, NULL, psxpad_spi_play_effect);
    162	if (err) {
    163		dev_err(&pad->spi->dev,
    164			"input_ff_create_memless() failed: %d\n", err);
    165		return err;
    166	}
    167
    168	return 0;
    169}
    170
    171#else	/* CONFIG_JOYSTICK_PSXPAD_SPI_FF */
    172
    173static void psxpad_control_motor(struct psxpad *pad,
    174				 bool motor1enable, bool motor2enable)
    175{
    176}
    177
    178static void psxpad_set_motor_level(struct psxpad *pad,
    179				   u8 motor1level, u8 motor2level)
    180{
    181}
    182
    183static inline int psxpad_spi_init_ff(struct psxpad *pad)
    184{
    185	return 0;
    186}
    187#endif	/* CONFIG_JOYSTICK_PSXPAD_SPI_FF */
    188
    189static int psxpad_spi_poll_open(struct input_dev *input)
    190{
    191	struct psxpad *pad = input_get_drvdata(input);
    192
    193	pm_runtime_get_sync(&pad->spi->dev);
    194
    195	return 0;
    196}
    197
    198static void psxpad_spi_poll_close(struct input_dev *input)
    199{
    200	struct psxpad *pad = input_get_drvdata(input);
    201
    202	pm_runtime_put_sync(&pad->spi->dev);
    203}
    204
    205static void psxpad_spi_poll(struct input_dev *input)
    206{
    207	struct psxpad *pad = input_get_drvdata(input);
    208	u8 b_rsp3, b_rsp4;
    209	int err;
    210
    211	psxpad_control_motor(pad, true, true);
    212
    213	memcpy(pad->sendbuf, PSX_CMD_POLL, sizeof(PSX_CMD_POLL));
    214	pad->sendbuf[3] = pad->motor1enable ? pad->motor1level : 0x00;
    215	pad->sendbuf[4] = pad->motor2enable ? pad->motor2level : 0x00;
    216	err = psxpad_command(pad, sizeof(PSX_CMD_POLL));
    217	if (err) {
    218		dev_err(&pad->spi->dev,
    219			"%s: poll command failed mode: %d\n", __func__, err);
    220		return;
    221	}
    222
    223	switch (pad->response[1]) {
    224	case 0xCE:	/* 0x73 : analog 1 */
    225		/* button data is inverted */
    226		b_rsp3 = ~pad->response[3];
    227		b_rsp4 = ~pad->response[4];
    228
    229		input_report_abs(input, ABS_X, REVERSE_BIT(pad->response[7]));
    230		input_report_abs(input, ABS_Y, REVERSE_BIT(pad->response[8]));
    231		input_report_abs(input, ABS_RX, REVERSE_BIT(pad->response[5]));
    232		input_report_abs(input, ABS_RY, REVERSE_BIT(pad->response[6]));
    233		input_report_key(input, BTN_DPAD_UP, b_rsp3 & BIT(3));
    234		input_report_key(input, BTN_DPAD_DOWN, b_rsp3 & BIT(1));
    235		input_report_key(input, BTN_DPAD_LEFT, b_rsp3 & BIT(0));
    236		input_report_key(input, BTN_DPAD_RIGHT, b_rsp3 & BIT(2));
    237		input_report_key(input, BTN_X, b_rsp4 & BIT(3));
    238		input_report_key(input, BTN_A, b_rsp4 & BIT(2));
    239		input_report_key(input, BTN_B, b_rsp4 & BIT(1));
    240		input_report_key(input, BTN_Y, b_rsp4 & BIT(0));
    241		input_report_key(input, BTN_TL, b_rsp4 & BIT(5));
    242		input_report_key(input, BTN_TR, b_rsp4 & BIT(4));
    243		input_report_key(input, BTN_TL2, b_rsp4 & BIT(7));
    244		input_report_key(input, BTN_TR2, b_rsp4 & BIT(6));
    245		input_report_key(input, BTN_THUMBL, b_rsp3 & BIT(6));
    246		input_report_key(input, BTN_THUMBR, b_rsp3 & BIT(5));
    247		input_report_key(input, BTN_SELECT, b_rsp3 & BIT(7));
    248		input_report_key(input, BTN_START, b_rsp3 & BIT(4));
    249		break;
    250
    251	case 0x82:	/* 0x41 : digital */
    252		/* button data is inverted */
    253		b_rsp3 = ~pad->response[3];
    254		b_rsp4 = ~pad->response[4];
    255
    256		input_report_abs(input, ABS_X, 0x80);
    257		input_report_abs(input, ABS_Y, 0x80);
    258		input_report_abs(input, ABS_RX, 0x80);
    259		input_report_abs(input, ABS_RY, 0x80);
    260		input_report_key(input, BTN_DPAD_UP, b_rsp3 & BIT(3));
    261		input_report_key(input, BTN_DPAD_DOWN, b_rsp3 & BIT(1));
    262		input_report_key(input, BTN_DPAD_LEFT, b_rsp3 & BIT(0));
    263		input_report_key(input, BTN_DPAD_RIGHT, b_rsp3 & BIT(2));
    264		input_report_key(input, BTN_X, b_rsp4 & BIT(3));
    265		input_report_key(input, BTN_A, b_rsp4 & BIT(2));
    266		input_report_key(input, BTN_B, b_rsp4 & BIT(1));
    267		input_report_key(input, BTN_Y, b_rsp4 & BIT(0));
    268		input_report_key(input, BTN_TL, b_rsp4 & BIT(5));
    269		input_report_key(input, BTN_TR, b_rsp4 & BIT(4));
    270		input_report_key(input, BTN_TL2, b_rsp4 & BIT(7));
    271		input_report_key(input, BTN_TR2, b_rsp4 & BIT(6));
    272		input_report_key(input, BTN_THUMBL, false);
    273		input_report_key(input, BTN_THUMBR, false);
    274		input_report_key(input, BTN_SELECT, b_rsp3 & BIT(7));
    275		input_report_key(input, BTN_START, b_rsp3 & BIT(4));
    276		break;
    277	}
    278
    279	input_sync(input);
    280}
    281
    282static int psxpad_spi_probe(struct spi_device *spi)
    283{
    284	struct psxpad *pad;
    285	struct input_dev *idev;
    286	int err;
    287
    288	pad = devm_kzalloc(&spi->dev, sizeof(struct psxpad), GFP_KERNEL);
    289	if (!pad)
    290		return -ENOMEM;
    291
    292	idev = devm_input_allocate_device(&spi->dev);
    293	if (!idev) {
    294		dev_err(&spi->dev, "failed to allocate input device\n");
    295		return -ENOMEM;
    296	}
    297
    298	/* input poll device settings */
    299	pad->idev = idev;
    300	pad->spi = spi;
    301
    302	/* input device settings */
    303	input_set_drvdata(idev, pad);
    304
    305	idev->name = "PlayStation 1/2 joypad";
    306	snprintf(pad->phys, sizeof(pad->phys), "%s/input", dev_name(&spi->dev));
    307	idev->id.bustype = BUS_SPI;
    308
    309	idev->open = psxpad_spi_poll_open;
    310	idev->close = psxpad_spi_poll_close;
    311
    312	/* key/value map settings */
    313	input_set_abs_params(idev, ABS_X, 0, 255, 0, 0);
    314	input_set_abs_params(idev, ABS_Y, 0, 255, 0, 0);
    315	input_set_abs_params(idev, ABS_RX, 0, 255, 0, 0);
    316	input_set_abs_params(idev, ABS_RY, 0, 255, 0, 0);
    317	input_set_capability(idev, EV_KEY, BTN_DPAD_UP);
    318	input_set_capability(idev, EV_KEY, BTN_DPAD_DOWN);
    319	input_set_capability(idev, EV_KEY, BTN_DPAD_LEFT);
    320	input_set_capability(idev, EV_KEY, BTN_DPAD_RIGHT);
    321	input_set_capability(idev, EV_KEY, BTN_A);
    322	input_set_capability(idev, EV_KEY, BTN_B);
    323	input_set_capability(idev, EV_KEY, BTN_X);
    324	input_set_capability(idev, EV_KEY, BTN_Y);
    325	input_set_capability(idev, EV_KEY, BTN_TL);
    326	input_set_capability(idev, EV_KEY, BTN_TR);
    327	input_set_capability(idev, EV_KEY, BTN_TL2);
    328	input_set_capability(idev, EV_KEY, BTN_TR2);
    329	input_set_capability(idev, EV_KEY, BTN_THUMBL);
    330	input_set_capability(idev, EV_KEY, BTN_THUMBR);
    331	input_set_capability(idev, EV_KEY, BTN_SELECT);
    332	input_set_capability(idev, EV_KEY, BTN_START);
    333
    334	err = psxpad_spi_init_ff(pad);
    335	if (err)
    336		return err;
    337
    338	/* SPI settings */
    339	spi->mode = SPI_MODE_3;
    340	spi->bits_per_word = 8;
    341	/* (PlayStation 1/2 joypad might be possible works 250kHz/500kHz) */
    342	spi->master->min_speed_hz = 125000;
    343	spi->master->max_speed_hz = 125000;
    344	spi_setup(spi);
    345
    346	/* pad settings */
    347	psxpad_set_motor_level(pad, 0, 0);
    348
    349
    350	err = input_setup_polling(idev, psxpad_spi_poll);
    351	if (err) {
    352		dev_err(&spi->dev, "failed to set up polling: %d\n", err);
    353		return err;
    354	}
    355
    356	/* poll interval is about 60fps */
    357	input_set_poll_interval(idev, 16);
    358	input_set_min_poll_interval(idev, 8);
    359	input_set_max_poll_interval(idev, 32);
    360
    361	/* register input poll device */
    362	err = input_register_device(idev);
    363	if (err) {
    364		dev_err(&spi->dev,
    365			"failed to register input device: %d\n", err);
    366		return err;
    367	}
    368
    369	pm_runtime_enable(&spi->dev);
    370
    371	return 0;
    372}
    373
    374static int __maybe_unused psxpad_spi_suspend(struct device *dev)
    375{
    376	struct spi_device *spi = to_spi_device(dev);
    377	struct psxpad *pad = spi_get_drvdata(spi);
    378
    379	psxpad_set_motor_level(pad, 0, 0);
    380
    381	return 0;
    382}
    383
    384static SIMPLE_DEV_PM_OPS(psxpad_spi_pm, psxpad_spi_suspend, NULL);
    385
    386static const struct spi_device_id psxpad_spi_id[] = {
    387	{ "psxpad-spi", 0 },
    388	{ }
    389};
    390MODULE_DEVICE_TABLE(spi, psxpad_spi_id);
    391
    392static struct spi_driver psxpad_spi_driver = {
    393	.driver = {
    394		.name = "psxpad-spi",
    395		.pm = &psxpad_spi_pm,
    396	},
    397	.id_table = psxpad_spi_id,
    398	.probe   = psxpad_spi_probe,
    399};
    400
    401module_spi_driver(psxpad_spi_driver);
    402
    403MODULE_AUTHOR("Tomohiro Yoshidomi <sylph23k@gmail.com>");
    404MODULE_DESCRIPTION("PlayStation 1/2 joypads via SPI interface Driver");
    405MODULE_LICENSE("GPL");