From 5b7c4cabbb65f5c469464da6c5f614cbd7f730f2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 21 Feb 2023 18:24:12 -0800 Subject: Merge tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next Pull networking updates from Jakub Kicinski: "Core: - Add dedicated kmem_cache for typical/small skb->head, avoid having to access struct page at kfree time, and improve memory use. - Introduce sysctl to set default RPS configuration for new netdevs. - Define Netlink protocol specification format which can be used to describe messages used by each family and auto-generate parsers. Add tools for generating kernel data structures and uAPI headers. - Expose all net/core sysctls inside netns. - Remove 4s sleep in netpoll if carrier is instantly detected on boot. - Add configurable limit of MDB entries per port, and port-vlan. - Continue populating drop reasons throughout the stack. - Retire a handful of legacy Qdiscs and classifiers. Protocols: - Support IPv4 big TCP (TSO frames larger than 64kB). - Add IP_LOCAL_PORT_RANGE socket option, to control local port range on socket by socket basis. - Track and report in procfs number of MPTCP sockets used. - Support mixing IPv4 and IPv6 flows in the in-kernel MPTCP path manager. - IPv6: don't check net.ipv6.route.max_size and rely on garbage collection to free memory (similarly to IPv4). - Support Penultimate Segment Pop (PSP) flavor in SRv6 (RFC8986). - ICMP: add per-rate limit counters. - Add support for user scanning requests in ieee802154. - Remove static WEP support. - Support minimal Wi-Fi 7 Extremely High Throughput (EHT) rate reporting. - WiFi 7 EHT channel puncturing support (client & AP). BPF: - Add a rbtree data structure following the "next-gen data structure" precedent set by recently added linked list, that is, by using kfunc + kptr instead of adding a new BPF map type. - Expose XDP hints via kfuncs with initial support for RX hash and timestamp metadata. - Add BPF_F_NO_TUNNEL_KEY extension to bpf_skb_set_tunnel_key to better support decap on GRE tunnel devices not operating in collect metadata. - Improve x86 JIT's codegen for PROBE_MEM runtime error checks. - Remove the need for trace_printk_lock for bpf_trace_printk and bpf_trace_vprintk helpers. - Extend libbpf's bpf_tracing.h support for tracing arguments of kprobes/uprobes and syscall as a special case. - Significantly reduce the search time for module symbols by livepatch and BPF. - Enable cpumasks to be used as kptrs, which is useful for tracing programs tracking which tasks end up running on which CPUs in different time intervals. - Add support for BPF trampoline on s390x and riscv64. - Add capability to export the XDP features supported by the NIC. - Add __bpf_kfunc tag for marking kernel functions as kfuncs. - Add cgroup.memory=nobpf kernel parameter option to disable BPF memory accounting for container environments. Netfilter: - Remove the CLUSTERIP target. It has been marked as obsolete for years, and we still have WARN splats wrt races of the out-of-band /proc interface installed by this target. - Add 'destroy' commands to nf_tables. They are identical to the existing 'delete' commands, but do not return an error if the referenced object (set, chain, rule...) did not exist. Driver API: - Improve cpumask_local_spread() locality to help NICs set the right IRQ affinity on AMD platforms. - Separate C22 and C45 MDIO bus transactions more clearly. - Introduce new DCB table to control DSCP rewrite on egress. - Support configuration of Physical Layer Collision Avoidance (PLCA) Reconciliation Sublayer (RS) (802.3cg-2019). Modern version of shared medium Ethernet. - Support for MAC Merge layer (IEEE 802.3-2018 clause 99). Allowing preemption of low priority frames by high priority frames. - Add support for controlling MACSec offload using netlink SET. - Rework devlink instance refcounts to allow registration and de-registration under the instance lock. Split the code into multiple files, drop some of the unnecessarily granular locks and factor out common parts of netlink operation handling. - Add TX frame aggregation parameters (for USB drivers). - Add a new attr TCA_EXT_WARN_MSG to report TC (offload) warning messages with notifications for debug. - Allow offloading of UDP NEW connections via act_ct. - Add support for per action HW stats in TC. - Support hardware miss to TC action (continue processing in SW from a specific point in the action chain). - Warn if old Wireless Extension user space interface is used with modern cfg80211/mac80211 drivers. Do not support Wireless Extensions for Wi-Fi 7 devices at all. Everyone should switch to using nl80211 interface instead. - Improve the CAN bit timing configuration. Use extack to return error messages directly to user space, update the SJW handling, including the definition of a new default value that will benefit CAN-FD controllers, by increasing their oscillator tolerance. New hardware / drivers: - Ethernet: - nVidia BlueField-3 support (control traffic driver) - Ethernet support for imx93 SoCs - Motorcomm yt8531 gigabit Ethernet PHY - onsemi NCN26000 10BASE-T1S PHY (with support for PLCA) - Microchip LAN8841 PHY (incl. cable diagnostics and PTP) - Amlogic gxl MDIO mux - WiFi: - RealTek RTL8188EU (rtl8xxxu) - Qualcomm Wi-Fi 7 devices (ath12k) - CAN: - Renesas R-Car V4H Drivers: - Bluetooth: - Set Per Platform Antenna Gain (PPAG) for Intel controllers. - Ethernet NICs: - Intel (1G, igc): - support TSN / Qbv / packet scheduling features of i226 model - Intel (100G, ice): - use GNSS subsystem instead of TTY - multi-buffer XDP support - extend support for GPIO pins to E823 devices - nVidia/Mellanox: - update the shared buffer configuration on PFC commands - implement PTP adjphase function for HW offset control - TC support for Geneve and GRE with VF tunnel offload - more efficient crypto key management method - multi-port eswitch support - Netronome/Corigine: - add DCB IEEE support - support IPsec offloading for NFP3800 - Freescale/NXP (enetc): - support XDP_REDIRECT for XDP non-linear buffers - improve reconfig, avoid link flap and waiting for idle - support MAC Merge layer - Other NICs: - sfc/ef100: add basic devlink support for ef100 - ionic: rx_push mode operation (writing descriptors via MMIO) - bnxt: use the auxiliary bus abstraction for RDMA - r8169: disable ASPM and reset bus in case of tx timeout - cpsw: support QSGMII mode for J721e CPSW9G - cpts: support pulse-per-second output - ngbe: add an mdio bus driver - usbnet: optimize usbnet_bh() by avoiding unnecessary queuing - r8152: handle devices with FW with NCM support - amd-xgbe: support 10Mbps, 2.5GbE speeds and rx-adaptation - virtio-net: support multi buffer XDP - virtio/vsock: replace virtio_vsock_pkt with sk_buff - tsnep: XDP support - Ethernet high-speed switches: - nVidia/Mellanox (mlxsw): - add support for latency TLV (in FW control messages) - Microchip (sparx5): - separate explicit and implicit traffic forwarding rules, make the implicit rules always active - add support for egress DSCP rewrite - IS0 VCAP support (Ingress Classification) - IS2 VCAP filters (protos, L3 addrs, L4 ports, flags, ToS etc.) - ES2 VCAP support (Egress Access Control) - support for Per-Stream Filtering and Policing (802.1Q, 8.6.5.1) - Ethernet embedded switches: - Marvell (mv88e6xxx): - add MAB (port auth) offload support - enable PTP receive for mv88e6390 - NXP (ocelot): - support MAC Merge layer - support for the the vsc7512 internal copper phys - Microchip: - lan9303: convert to PHYLINK - lan966x: support TC flower filter statistics - lan937x: PTP support for KSZ9563/KSZ8563 and LAN937x - lan937x: support Credit Based Shaper configuration - ksz9477: support Energy Efficient Ethernet - other: - qca8k: convert to regmap read/write API, use bulk operations - rswitch: Improve TX timestamp accuracy - Intel WiFi (iwlwifi): - EHT (Wi-Fi 7) rate reporting - STEP equalizer support: transfer some STEP (connection to radio on platforms with integrated wifi) related parameters from the BIOS to the firmware. - Qualcomm 802.11ax WiFi (ath11k): - IPQ5018 support - Fine Timing Measurement (FTM) responder role support - channel 177 support - MediaTek WiFi (mt76): - per-PHY LED support - mt7996: EHT (Wi-Fi 7) support - Wireless Ethernet Dispatch (WED) reset support - switch to using page pool allocator - RealTek WiFi (rtw89): - support new version of Bluetooth co-existance - Mobile: - rmnet: support TX aggregation" * tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1872 commits) page_pool: add a comment explaining the fragment counter usage net: ethtool: fix __ethtool_dev_mm_supported() implementation ethtool: pse-pd: Fix double word in comments xsk: add linux/vmalloc.h to xsk.c sefltests: netdevsim: wait for devlink instance after netns removal selftest: fib_tests: Always cleanup before exit net/mlx5e: Align IPsec ASO result memory to be as required by hardware net/mlx5e: TC, Set CT miss to the specific ct action instance net/mlx5e: Rename CHAIN_TO_REG to MAPPED_OBJ_TO_REG net/mlx5: Refactor tc miss handling to a single function net/mlx5: Kconfig: Make tc offload depend on tc skb extension net/sched: flower: Support hardware miss to tc action net/sched: flower: Move filter handle initialization earlier net/sched: cls_api: Support hardware miss to tc action net/sched: Rename user cookie and act cookie sfc: fix builds without CONFIG_RTC_LIB sfc: clean up some inconsistent indentings net/mlx4_en: Introduce flexible array to silence overflow warning net: lan966x: Fix possible deadlock inside PTP net/ulp: Remove redundant ->clone() test in inet_clone_ulp(). ... --- drivers/input/serio/libps2.c | 494 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 494 insertions(+) create mode 100644 drivers/input/serio/libps2.c (limited to 'drivers/input/serio/libps2.c') diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c new file mode 100644 index 000000000..3e19344ed --- /dev/null +++ b/drivers/input/serio/libps2.c @@ -0,0 +1,494 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * PS/2 driver library + * + * Copyright (c) 1999-2002 Vojtech Pavlik + * Copyright (c) 2004 Dmitry Torokhov + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_DESC "PS/2 driver library" + +MODULE_AUTHOR("Dmitry Torokhov "); +MODULE_DESCRIPTION("PS/2 driver library"); +MODULE_LICENSE("GPL"); + +static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte, + unsigned int timeout, unsigned int max_attempts) + __releases(&ps2dev->serio->lock) __acquires(&ps2dev->serio->lock) +{ + int attempt = 0; + int error; + + lockdep_assert_held(&ps2dev->serio->lock); + + do { + ps2dev->nak = 1; + ps2dev->flags |= PS2_FLAG_ACK; + + serio_continue_rx(ps2dev->serio); + + error = serio_write(ps2dev->serio, byte); + if (error) + dev_dbg(&ps2dev->serio->dev, + "failed to write %#02x: %d\n", byte, error); + else + wait_event_timeout(ps2dev->wait, + !(ps2dev->flags & PS2_FLAG_ACK), + msecs_to_jiffies(timeout)); + + serio_pause_rx(ps2dev->serio); + } while (ps2dev->nak == PS2_RET_NAK && ++attempt < max_attempts); + + ps2dev->flags &= ~PS2_FLAG_ACK; + + if (!error) { + switch (ps2dev->nak) { + case 0: + break; + case PS2_RET_NAK: + error = -EAGAIN; + break; + case PS2_RET_ERR: + error = -EPROTO; + break; + default: + error = -EIO; + break; + } + } + + if (error || attempt > 1) + dev_dbg(&ps2dev->serio->dev, + "%02x - %d (%x), attempt %d\n", + byte, error, ps2dev->nak, attempt); + + return error; +} + +/* + * ps2_sendbyte() sends a byte to the device and waits for acknowledge. + * It doesn't handle retransmission, the caller is expected to handle + * it when needed. + * + * ps2_sendbyte() can only be called from a process context. + */ + +int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout) +{ + int retval; + + serio_pause_rx(ps2dev->serio); + + retval = ps2_do_sendbyte(ps2dev, byte, timeout, 1); + dev_dbg(&ps2dev->serio->dev, "%02x - %x\n", byte, ps2dev->nak); + + serio_continue_rx(ps2dev->serio); + + return retval; +} +EXPORT_SYMBOL(ps2_sendbyte); + +void ps2_begin_command(struct ps2dev *ps2dev) +{ + struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex; + + mutex_lock(m); +} +EXPORT_SYMBOL(ps2_begin_command); + +void ps2_end_command(struct ps2dev *ps2dev) +{ + struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex; + + mutex_unlock(m); +} +EXPORT_SYMBOL(ps2_end_command); + +/* + * ps2_drain() waits for device to transmit requested number of bytes + * and discards them. + */ + +void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout) +{ + if (maxbytes > sizeof(ps2dev->cmdbuf)) { + WARN_ON(1); + maxbytes = sizeof(ps2dev->cmdbuf); + } + + ps2_begin_command(ps2dev); + + serio_pause_rx(ps2dev->serio); + ps2dev->flags = PS2_FLAG_CMD; + ps2dev->cmdcnt = maxbytes; + serio_continue_rx(ps2dev->serio); + + wait_event_timeout(ps2dev->wait, + !(ps2dev->flags & PS2_FLAG_CMD), + msecs_to_jiffies(timeout)); + + ps2_end_command(ps2dev); +} +EXPORT_SYMBOL(ps2_drain); + +/* + * ps2_is_keyboard_id() checks received ID byte against the list of + * known keyboard IDs. + */ + +bool ps2_is_keyboard_id(u8 id_byte) +{ + static const u8 keyboard_ids[] = { + 0xab, /* Regular keyboards */ + 0xac, /* NCD Sun keyboard */ + 0x2b, /* Trust keyboard, translated */ + 0x5d, /* Trust keyboard */ + 0x60, /* NMB SGI keyboard, translated */ + 0x47, /* NMB SGI keyboard */ + }; + + return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL; +} +EXPORT_SYMBOL(ps2_is_keyboard_id); + +/* + * ps2_adjust_timeout() is called after receiving 1st byte of command + * response and tries to reduce remaining timeout to speed up command + * completion. + */ + +static int ps2_adjust_timeout(struct ps2dev *ps2dev, + unsigned int command, unsigned int timeout) +{ + switch (command) { + case PS2_CMD_RESET_BAT: + /* + * Device has sent the first response byte after + * reset command, reset is thus done, so we can + * shorten the timeout. + * The next byte will come soon (keyboard) or not + * at all (mouse). + */ + if (timeout > msecs_to_jiffies(100)) + timeout = msecs_to_jiffies(100); + break; + + case PS2_CMD_GETID: + /* + * Microsoft Natural Elite keyboard responds to + * the GET ID command as it were a mouse, with + * a single byte. Fail the command so atkbd will + * use alternative probe to detect it. + */ + if (ps2dev->cmdbuf[1] == 0xaa) { + serio_pause_rx(ps2dev->serio); + ps2dev->flags = 0; + serio_continue_rx(ps2dev->serio); + timeout = 0; + } + + /* + * If device behind the port is not a keyboard there + * won't be 2nd byte of ID response. + */ + if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) { + serio_pause_rx(ps2dev->serio); + ps2dev->flags = ps2dev->cmdcnt = 0; + serio_continue_rx(ps2dev->serio); + timeout = 0; + } + break; + + default: + break; + } + + return timeout; +} + +/* + * ps2_command() sends a command and its parameters to the mouse, + * then waits for the response and puts it in the param array. + * + * ps2_command() can only be called from a process context + */ + +int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command) +{ + unsigned int timeout; + unsigned int send = (command >> 12) & 0xf; + unsigned int receive = (command >> 8) & 0xf; + int rc; + int i; + u8 send_param[16]; + + if (receive > sizeof(ps2dev->cmdbuf)) { + WARN_ON(1); + return -EINVAL; + } + + if (send && !param) { + WARN_ON(1); + return -EINVAL; + } + + memcpy(send_param, param, send); + + serio_pause_rx(ps2dev->serio); + + ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0; + ps2dev->cmdcnt = receive; + if (receive && param) + for (i = 0; i < receive; i++) + ps2dev->cmdbuf[(receive - 1) - i] = param[i]; + + /* Signal that we are sending the command byte */ + ps2dev->flags |= PS2_FLAG_ACK_CMD; + + /* + * Some devices (Synaptics) peform the reset before + * ACKing the reset command, and so it can take a long + * time before the ACK arrives. + */ + timeout = command == PS2_CMD_RESET_BAT ? 1000 : 200; + + rc = ps2_do_sendbyte(ps2dev, command & 0xff, timeout, 2); + if (rc) + goto out_reset_flags; + + /* Now we are sending command parameters, if any */ + ps2dev->flags &= ~PS2_FLAG_ACK_CMD; + + for (i = 0; i < send; i++) { + rc = ps2_do_sendbyte(ps2dev, param[i], 200, 2); + if (rc) + goto out_reset_flags; + } + + serio_continue_rx(ps2dev->serio); + + /* + * The reset command takes a long time to execute. + */ + timeout = msecs_to_jiffies(command == PS2_CMD_RESET_BAT ? 4000 : 500); + + timeout = wait_event_timeout(ps2dev->wait, + !(ps2dev->flags & PS2_FLAG_CMD1), timeout); + + if (ps2dev->cmdcnt && !(ps2dev->flags & PS2_FLAG_CMD1)) { + + timeout = ps2_adjust_timeout(ps2dev, command, timeout); + wait_event_timeout(ps2dev->wait, + !(ps2dev->flags & PS2_FLAG_CMD), timeout); + } + + serio_pause_rx(ps2dev->serio); + + if (param) { + for (i = 0; i < receive; i++) + param[i] = ps2dev->cmdbuf[(receive - 1) - i]; + kmsan_unpoison_memory(param, receive); + } + + if (ps2dev->cmdcnt && + (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1)) { + rc = -EPROTO; + goto out_reset_flags; + } + + rc = 0; + + out_reset_flags: + ps2dev->flags = 0; + serio_continue_rx(ps2dev->serio); + + dev_dbg(&ps2dev->serio->dev, + "%02x [%*ph] - %x/%08lx [%*ph]\n", + command & 0xff, send, send_param, + ps2dev->nak, ps2dev->flags, + receive, param ?: send_param); + + /* + * ps_command() handles resends itself, so do not leak -EAGAIN + * to the callers. + */ + return rc != -EAGAIN ? rc : -EPROTO; +} +EXPORT_SYMBOL(__ps2_command); + +int ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command) +{ + int rc; + + ps2_begin_command(ps2dev); + rc = __ps2_command(ps2dev, param, command); + ps2_end_command(ps2dev); + + return rc; +} +EXPORT_SYMBOL(ps2_command); + +/* + * ps2_sliced_command() sends an extended PS/2 command to the mouse + * using sliced syntax, understood by advanced devices, such as Logitech + * or Synaptics touchpads. The command is encoded as: + * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu + * is the command. + */ + +int ps2_sliced_command(struct ps2dev *ps2dev, u8 command) +{ + int i; + int retval; + + ps2_begin_command(ps2dev); + + retval = __ps2_command(ps2dev, NULL, PS2_CMD_SETSCALE11); + if (retval) + goto out; + + for (i = 6; i >= 0; i -= 2) { + u8 d = (command >> i) & 3; + retval = __ps2_command(ps2dev, &d, PS2_CMD_SETRES); + if (retval) + break; + } + +out: + dev_dbg(&ps2dev->serio->dev, "%02x - %d\n", command, retval); + ps2_end_command(ps2dev); + return retval; +} +EXPORT_SYMBOL(ps2_sliced_command); + +/* + * ps2_init() initializes ps2dev structure + */ + +void ps2_init(struct ps2dev *ps2dev, struct serio *serio) +{ + mutex_init(&ps2dev->cmd_mutex); + lockdep_set_subclass(&ps2dev->cmd_mutex, serio->depth); + init_waitqueue_head(&ps2dev->wait); + ps2dev->serio = serio; +} +EXPORT_SYMBOL(ps2_init); + +/* + * ps2_handle_ack() is supposed to be used in interrupt handler + * to properly process ACK/NAK of a command from a PS/2 device. + */ + +bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data) +{ + switch (data) { + case PS2_RET_ACK: + ps2dev->nak = 0; + break; + + case PS2_RET_NAK: + ps2dev->flags |= PS2_FLAG_NAK; + ps2dev->nak = PS2_RET_NAK; + break; + + case PS2_RET_ERR: + if (ps2dev->flags & PS2_FLAG_NAK) { + ps2dev->flags &= ~PS2_FLAG_NAK; + ps2dev->nak = PS2_RET_ERR; + break; + } + fallthrough; + + /* + * Workaround for mice which don't ACK the Get ID command. + * These are valid mouse IDs that we recognize. + */ + case 0x00: + case 0x03: + case 0x04: + if (ps2dev->flags & PS2_FLAG_WAITID) { + ps2dev->nak = 0; + break; + } + fallthrough; + default: + /* + * Do not signal errors if we get unexpected reply while + * waiting for an ACK to the initial (first) command byte: + * the device might not be quiesced yet and continue + * delivering data. + * Note that we reset PS2_FLAG_WAITID flag, so the workaround + * for mice not acknowledging the Get ID command only triggers + * on the 1st byte; if device spews data we really want to see + * a real ACK from it. + */ + dev_dbg(&ps2dev->serio->dev, "unexpected %#02x\n", data); + ps2dev->flags &= ~PS2_FLAG_WAITID; + return ps2dev->flags & PS2_FLAG_ACK_CMD; + } + + if (!ps2dev->nak) { + ps2dev->flags &= ~PS2_FLAG_NAK; + if (ps2dev->cmdcnt) + ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1; + } + + ps2dev->flags &= ~PS2_FLAG_ACK; + wake_up(&ps2dev->wait); + + if (data != PS2_RET_ACK) + ps2_handle_response(ps2dev, data); + + return true; +} +EXPORT_SYMBOL(ps2_handle_ack); + +/* + * ps2_handle_response() is supposed to be used in interrupt handler + * to properly store device's response to a command and notify process + * waiting for completion of the command. + */ + +bool ps2_handle_response(struct ps2dev *ps2dev, u8 data) +{ + if (ps2dev->cmdcnt) + ps2dev->cmdbuf[--ps2dev->cmdcnt] = data; + + if (ps2dev->flags & PS2_FLAG_CMD1) { + ps2dev->flags &= ~PS2_FLAG_CMD1; + if (ps2dev->cmdcnt) + wake_up(&ps2dev->wait); + } + + if (!ps2dev->cmdcnt) { + ps2dev->flags &= ~PS2_FLAG_CMD; + wake_up(&ps2dev->wait); + } + + return true; +} +EXPORT_SYMBOL(ps2_handle_response); + +void ps2_cmd_aborted(struct ps2dev *ps2dev) +{ + if (ps2dev->flags & PS2_FLAG_ACK) + ps2dev->nak = 1; + + if (ps2dev->flags & (PS2_FLAG_ACK | PS2_FLAG_CMD)) + wake_up(&ps2dev->wait); + + /* reset all flags except last nack */ + ps2dev->flags &= PS2_FLAG_NAK; +} +EXPORT_SYMBOL(ps2_cmd_aborted); -- cgit v1.2.3