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

ps2-gpio.c (12647B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * GPIO based serio bus driver for bit banging the PS/2 protocol
      4 *
      5 * Author: Danilo Krummrich <danilokrummrich@dk-develop.de>
      6 */
      7
      8#include <linux/gpio/consumer.h>
      9#include <linux/interrupt.h>
     10#include <linux/module.h>
     11#include <linux/serio.h>
     12#include <linux/slab.h>
     13#include <linux/platform_device.h>
     14#include <linux/workqueue.h>
     15#include <linux/completion.h>
     16#include <linux/mutex.h>
     17#include <linux/preempt.h>
     18#include <linux/property.h>
     19#include <linux/of.h>
     20#include <linux/jiffies.h>
     21#include <linux/delay.h>
     22#include <linux/timekeeping.h>
     23
     24#define DRIVER_NAME		"ps2-gpio"
     25
     26#define PS2_MODE_RX		0
     27#define PS2_MODE_TX		1
     28
     29#define PS2_START_BIT		0
     30#define PS2_DATA_BIT0		1
     31#define PS2_DATA_BIT1		2
     32#define PS2_DATA_BIT2		3
     33#define PS2_DATA_BIT3		4
     34#define PS2_DATA_BIT4		5
     35#define PS2_DATA_BIT5		6
     36#define PS2_DATA_BIT6		7
     37#define PS2_DATA_BIT7		8
     38#define PS2_PARITY_BIT		9
     39#define PS2_STOP_BIT		10
     40#define PS2_ACK_BIT		11
     41
     42#define PS2_DEV_RET_ACK		0xfa
     43#define PS2_DEV_RET_NACK	0xfe
     44
     45#define PS2_CMD_RESEND		0xfe
     46
     47/*
     48 * The PS2 protocol specifies a clock frequency between 10kHz and 16.7kHz,
     49 * therefore the maximal interrupt interval should be 100us and the minimum
     50 * interrupt interval should be ~60us. Let's allow +/- 20us for frequency
     51 * deviations and interrupt latency.
     52 *
     53 * The data line must be samples after ~30us to 50us after the falling edge,
     54 * since the device updates the data line at the rising edge.
     55 *
     56 * ___            ______            ______            ______            ___
     57 *    \          /      \          /      \          /      \          /
     58 *     \        /        \        /        \        /        \        /
     59 *      \______/          \______/          \______/          \______/
     60 *
     61 *     |-----------------|                 |--------|
     62 *          60us/100us                      30us/50us
     63 */
     64#define PS2_CLK_FREQ_MIN_HZ		10000
     65#define PS2_CLK_FREQ_MAX_HZ		16700
     66#define PS2_CLK_MIN_INTERVAL_US		((1000 * 1000) / PS2_CLK_FREQ_MAX_HZ)
     67#define PS2_CLK_MAX_INTERVAL_US		((1000 * 1000) / PS2_CLK_FREQ_MIN_HZ)
     68#define PS2_IRQ_MIN_INTERVAL_US		(PS2_CLK_MIN_INTERVAL_US - 20)
     69#define PS2_IRQ_MAX_INTERVAL_US		(PS2_CLK_MAX_INTERVAL_US + 20)
     70
     71struct ps2_gpio_data {
     72	struct device *dev;
     73	struct serio *serio;
     74	unsigned char mode;
     75	struct gpio_desc *gpio_clk;
     76	struct gpio_desc *gpio_data;
     77	bool write_enable;
     78	int irq;
     79	ktime_t t_irq_now;
     80	ktime_t t_irq_last;
     81	struct {
     82		unsigned char cnt;
     83		unsigned char byte;
     84	} rx;
     85	struct {
     86		unsigned char cnt;
     87		unsigned char byte;
     88		ktime_t t_xfer_start;
     89		ktime_t t_xfer_end;
     90		struct completion complete;
     91		struct mutex mutex;
     92		struct delayed_work work;
     93	} tx;
     94};
     95
     96static int ps2_gpio_open(struct serio *serio)
     97{
     98	struct ps2_gpio_data *drvdata = serio->port_data;
     99
    100	drvdata->t_irq_last = 0;
    101	drvdata->tx.t_xfer_end = 0;
    102
    103	enable_irq(drvdata->irq);
    104	return 0;
    105}
    106
    107static void ps2_gpio_close(struct serio *serio)
    108{
    109	struct ps2_gpio_data *drvdata = serio->port_data;
    110
    111	flush_delayed_work(&drvdata->tx.work);
    112	disable_irq(drvdata->irq);
    113}
    114
    115static int __ps2_gpio_write(struct serio *serio, unsigned char val)
    116{
    117	struct ps2_gpio_data *drvdata = serio->port_data;
    118
    119	disable_irq_nosync(drvdata->irq);
    120	gpiod_direction_output(drvdata->gpio_clk, 0);
    121
    122	drvdata->mode = PS2_MODE_TX;
    123	drvdata->tx.byte = val;
    124
    125	schedule_delayed_work(&drvdata->tx.work, usecs_to_jiffies(200));
    126
    127	return 0;
    128}
    129
    130static int ps2_gpio_write(struct serio *serio, unsigned char val)
    131{
    132	struct ps2_gpio_data *drvdata = serio->port_data;
    133	int ret = 0;
    134
    135	if (in_task()) {
    136		mutex_lock(&drvdata->tx.mutex);
    137		__ps2_gpio_write(serio, val);
    138		if (!wait_for_completion_timeout(&drvdata->tx.complete,
    139						 msecs_to_jiffies(10000)))
    140			ret = SERIO_TIMEOUT;
    141		mutex_unlock(&drvdata->tx.mutex);
    142	} else {
    143		__ps2_gpio_write(serio, val);
    144	}
    145
    146	return ret;
    147}
    148
    149static void ps2_gpio_tx_work_fn(struct work_struct *work)
    150{
    151	struct delayed_work *dwork = to_delayed_work(work);
    152	struct ps2_gpio_data *drvdata = container_of(dwork,
    153						     struct ps2_gpio_data,
    154						     tx.work);
    155
    156	drvdata->tx.t_xfer_start = ktime_get();
    157	enable_irq(drvdata->irq);
    158	gpiod_direction_output(drvdata->gpio_data, 0);
    159	gpiod_direction_input(drvdata->gpio_clk);
    160}
    161
    162static irqreturn_t ps2_gpio_irq_rx(struct ps2_gpio_data *drvdata)
    163{
    164	unsigned char byte, cnt;
    165	int data;
    166	int rxflags = 0;
    167	s64 us_delta;
    168
    169	byte = drvdata->rx.byte;
    170	cnt = drvdata->rx.cnt;
    171
    172	drvdata->t_irq_now = ktime_get();
    173
    174	/*
    175	 * We need to consider spurious interrupts happening right after
    176	 * a TX xfer finished.
    177	 */
    178	us_delta = ktime_us_delta(drvdata->t_irq_now, drvdata->tx.t_xfer_end);
    179	if (unlikely(us_delta < PS2_IRQ_MIN_INTERVAL_US))
    180		goto end;
    181
    182	us_delta = ktime_us_delta(drvdata->t_irq_now, drvdata->t_irq_last);
    183	if (us_delta > PS2_IRQ_MAX_INTERVAL_US && cnt) {
    184		dev_err(drvdata->dev,
    185			"RX: timeout, probably we missed an interrupt\n");
    186		goto err;
    187	} else if (unlikely(us_delta < PS2_IRQ_MIN_INTERVAL_US)) {
    188		/* Ignore spurious IRQs. */
    189		goto end;
    190	}
    191	drvdata->t_irq_last = drvdata->t_irq_now;
    192
    193	data = gpiod_get_value(drvdata->gpio_data);
    194	if (unlikely(data < 0)) {
    195		dev_err(drvdata->dev, "RX: failed to get data gpio val: %d\n",
    196			data);
    197		goto err;
    198	}
    199
    200	switch (cnt) {
    201	case PS2_START_BIT:
    202		/* start bit should be low */
    203		if (unlikely(data)) {
    204			dev_err(drvdata->dev, "RX: start bit should be low\n");
    205			goto err;
    206		}
    207		break;
    208	case PS2_DATA_BIT0:
    209	case PS2_DATA_BIT1:
    210	case PS2_DATA_BIT2:
    211	case PS2_DATA_BIT3:
    212	case PS2_DATA_BIT4:
    213	case PS2_DATA_BIT5:
    214	case PS2_DATA_BIT6:
    215	case PS2_DATA_BIT7:
    216		/* processing data bits */
    217		if (data)
    218			byte |= (data << (cnt - 1));
    219		break;
    220	case PS2_PARITY_BIT:
    221		/* check odd parity */
    222		if (!((hweight8(byte) & 1) ^ data)) {
    223			rxflags |= SERIO_PARITY;
    224			dev_warn(drvdata->dev, "RX: parity error\n");
    225			if (!drvdata->write_enable)
    226				goto err;
    227		}
    228		break;
    229	case PS2_STOP_BIT:
    230		/* stop bit should be high */
    231		if (unlikely(!data)) {
    232			dev_err(drvdata->dev, "RX: stop bit should be high\n");
    233			goto err;
    234		}
    235
    236		/*
    237		 * Do not send spurious ACK's and NACK's when write fn is
    238		 * not provided.
    239		 */
    240		if (!drvdata->write_enable) {
    241			if (byte == PS2_DEV_RET_NACK)
    242				goto err;
    243			else if (byte == PS2_DEV_RET_ACK)
    244				break;
    245		}
    246
    247		serio_interrupt(drvdata->serio, byte, rxflags);
    248		dev_dbg(drvdata->dev, "RX: sending byte 0x%x\n", byte);
    249
    250		cnt = byte = 0;
    251
    252		goto end; /* success */
    253	default:
    254		dev_err(drvdata->dev, "RX: got out of sync with the device\n");
    255		goto err;
    256	}
    257
    258	cnt++;
    259	goto end; /* success */
    260
    261err:
    262	cnt = byte = 0;
    263	__ps2_gpio_write(drvdata->serio, PS2_CMD_RESEND);
    264end:
    265	drvdata->rx.cnt = cnt;
    266	drvdata->rx.byte = byte;
    267	return IRQ_HANDLED;
    268}
    269
    270static irqreturn_t ps2_gpio_irq_tx(struct ps2_gpio_data *drvdata)
    271{
    272	unsigned char byte, cnt;
    273	int data;
    274	s64 us_delta;
    275
    276	cnt = drvdata->tx.cnt;
    277	byte = drvdata->tx.byte;
    278
    279	drvdata->t_irq_now = ktime_get();
    280
    281	/*
    282	 * There might be pending IRQs since we disabled IRQs in
    283	 * __ps2_gpio_write().  We can expect at least one clock period until
    284	 * the device generates the first falling edge after releasing the
    285	 * clock line.
    286	 */
    287	us_delta = ktime_us_delta(drvdata->t_irq_now,
    288				  drvdata->tx.t_xfer_start);
    289	if (unlikely(us_delta < PS2_CLK_MIN_INTERVAL_US))
    290		goto end;
    291
    292	us_delta = ktime_us_delta(drvdata->t_irq_now, drvdata->t_irq_last);
    293	if (us_delta > PS2_IRQ_MAX_INTERVAL_US && cnt > 1) {
    294		dev_err(drvdata->dev,
    295			"TX: timeout, probably we missed an interrupt\n");
    296		goto err;
    297	} else if (unlikely(us_delta < PS2_IRQ_MIN_INTERVAL_US)) {
    298		/* Ignore spurious IRQs. */
    299		goto end;
    300	}
    301	drvdata->t_irq_last = drvdata->t_irq_now;
    302
    303	switch (cnt) {
    304	case PS2_START_BIT:
    305		/* should never happen */
    306		dev_err(drvdata->dev,
    307			"TX: start bit should have been sent already\n");
    308		goto err;
    309	case PS2_DATA_BIT0:
    310	case PS2_DATA_BIT1:
    311	case PS2_DATA_BIT2:
    312	case PS2_DATA_BIT3:
    313	case PS2_DATA_BIT4:
    314	case PS2_DATA_BIT5:
    315	case PS2_DATA_BIT6:
    316	case PS2_DATA_BIT7:
    317		data = byte & BIT(cnt - 1);
    318		gpiod_set_value(drvdata->gpio_data, data);
    319		break;
    320	case PS2_PARITY_BIT:
    321		/* do odd parity */
    322		data = !(hweight8(byte) & 1);
    323		gpiod_set_value(drvdata->gpio_data, data);
    324		break;
    325	case PS2_STOP_BIT:
    326		/* release data line to generate stop bit */
    327		gpiod_direction_input(drvdata->gpio_data);
    328		break;
    329	case PS2_ACK_BIT:
    330		data = gpiod_get_value(drvdata->gpio_data);
    331		if (data) {
    332			dev_warn(drvdata->dev, "TX: received NACK, retry\n");
    333			goto err;
    334		}
    335
    336		drvdata->tx.t_xfer_end = ktime_get();
    337		drvdata->mode = PS2_MODE_RX;
    338		complete(&drvdata->tx.complete);
    339
    340		cnt = 1;
    341		goto end; /* success */
    342	default:
    343		/*
    344		 * Probably we missed the stop bit. Therefore we release data
    345		 * line and try again.
    346		 */
    347		gpiod_direction_input(drvdata->gpio_data);
    348		dev_err(drvdata->dev, "TX: got out of sync with the device\n");
    349		goto err;
    350	}
    351
    352	cnt++;
    353	goto end; /* success */
    354
    355err:
    356	cnt = 1;
    357	gpiod_direction_input(drvdata->gpio_data);
    358	__ps2_gpio_write(drvdata->serio, drvdata->tx.byte);
    359end:
    360	drvdata->tx.cnt = cnt;
    361	return IRQ_HANDLED;
    362}
    363
    364static irqreturn_t ps2_gpio_irq(int irq, void *dev_id)
    365{
    366	struct ps2_gpio_data *drvdata = dev_id;
    367
    368	return drvdata->mode ? ps2_gpio_irq_tx(drvdata) :
    369		ps2_gpio_irq_rx(drvdata);
    370}
    371
    372static int ps2_gpio_get_props(struct device *dev,
    373				 struct ps2_gpio_data *drvdata)
    374{
    375	enum gpiod_flags gflags;
    376
    377	/* Enforce open drain, since this is required by the PS/2 bus. */
    378	gflags = GPIOD_IN | GPIOD_FLAGS_BIT_OPEN_DRAIN;
    379
    380	drvdata->gpio_data = devm_gpiod_get(dev, "data", gflags);
    381	if (IS_ERR(drvdata->gpio_data)) {
    382		dev_err(dev, "failed to request data gpio: %ld",
    383			PTR_ERR(drvdata->gpio_data));
    384		return PTR_ERR(drvdata->gpio_data);
    385	}
    386
    387	drvdata->gpio_clk = devm_gpiod_get(dev, "clk", gflags);
    388	if (IS_ERR(drvdata->gpio_clk)) {
    389		dev_err(dev, "failed to request clock gpio: %ld",
    390			PTR_ERR(drvdata->gpio_clk));
    391		return PTR_ERR(drvdata->gpio_clk);
    392	}
    393
    394	drvdata->write_enable = device_property_read_bool(dev,
    395				"write-enable");
    396
    397	return 0;
    398}
    399
    400static int ps2_gpio_probe(struct platform_device *pdev)
    401{
    402	struct ps2_gpio_data *drvdata;
    403	struct serio *serio;
    404	struct device *dev = &pdev->dev;
    405	int error;
    406
    407	drvdata = devm_kzalloc(dev, sizeof(struct ps2_gpio_data), GFP_KERNEL);
    408	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
    409	if (!drvdata || !serio) {
    410		error = -ENOMEM;
    411		goto err_free_serio;
    412	}
    413
    414	error = ps2_gpio_get_props(dev, drvdata);
    415	if (error)
    416		goto err_free_serio;
    417
    418	if (gpiod_cansleep(drvdata->gpio_data) ||
    419	    gpiod_cansleep(drvdata->gpio_clk)) {
    420		dev_err(dev, "GPIO data or clk are connected via slow bus\n");
    421		error = -EINVAL;
    422		goto err_free_serio;
    423	}
    424
    425	drvdata->irq = platform_get_irq(pdev, 0);
    426	if (drvdata->irq < 0) {
    427		error = drvdata->irq;
    428		goto err_free_serio;
    429	}
    430
    431	error = devm_request_irq(dev, drvdata->irq, ps2_gpio_irq,
    432				 IRQF_NO_THREAD, DRIVER_NAME, drvdata);
    433	if (error) {
    434		dev_err(dev, "failed to request irq %d: %d\n",
    435			drvdata->irq, error);
    436		goto err_free_serio;
    437	}
    438
    439	/* Keep irq disabled until serio->open is called. */
    440	disable_irq(drvdata->irq);
    441
    442	serio->id.type = SERIO_8042;
    443	serio->open = ps2_gpio_open;
    444	serio->close = ps2_gpio_close;
    445	/*
    446	 * Write can be enabled in platform/dt data, but possibly it will not
    447	 * work because of the tough timings.
    448	 */
    449	serio->write = drvdata->write_enable ? ps2_gpio_write : NULL;
    450	serio->port_data = drvdata;
    451	serio->dev.parent = dev;
    452	strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
    453	strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
    454
    455	drvdata->serio = serio;
    456	drvdata->dev = dev;
    457	drvdata->mode = PS2_MODE_RX;
    458
    459	/*
    460	 * Tx count always starts at 1, as the start bit is sent implicitly by
    461	 * host-to-device communication initialization.
    462	 */
    463	drvdata->tx.cnt = 1;
    464
    465	INIT_DELAYED_WORK(&drvdata->tx.work, ps2_gpio_tx_work_fn);
    466	init_completion(&drvdata->tx.complete);
    467	mutex_init(&drvdata->tx.mutex);
    468
    469	serio_register_port(serio);
    470	platform_set_drvdata(pdev, drvdata);
    471
    472	return 0;	/* success */
    473
    474err_free_serio:
    475	kfree(serio);
    476	return error;
    477}
    478
    479static int ps2_gpio_remove(struct platform_device *pdev)
    480{
    481	struct ps2_gpio_data *drvdata = platform_get_drvdata(pdev);
    482
    483	serio_unregister_port(drvdata->serio);
    484	return 0;
    485}
    486
    487#if defined(CONFIG_OF)
    488static const struct of_device_id ps2_gpio_match[] = {
    489	{ .compatible = "ps2-gpio", },
    490	{ },
    491};
    492MODULE_DEVICE_TABLE(of, ps2_gpio_match);
    493#endif
    494
    495static struct platform_driver ps2_gpio_driver = {
    496	.probe		= ps2_gpio_probe,
    497	.remove		= ps2_gpio_remove,
    498	.driver = {
    499		.name = DRIVER_NAME,
    500		.of_match_table = of_match_ptr(ps2_gpio_match),
    501	},
    502};
    503module_platform_driver(ps2_gpio_driver);
    504
    505MODULE_AUTHOR("Danilo Krummrich <danilokrummrich@dk-develop.de>");
    506MODULE_DESCRIPTION("GPIO PS2 driver");
    507MODULE_LICENSE("GPL v2");