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

ehset.c (5764B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
      4 */
      5
      6#include <linux/kernel.h>
      7#include <linux/errno.h>
      8#include <linux/module.h>
      9#include <linux/slab.h>
     10#include <linux/usb.h>
     11#include <linux/usb/ch11.h>
     12
     13#define TEST_SE0_NAK_PID			0x0101
     14#define TEST_J_PID				0x0102
     15#define TEST_K_PID				0x0103
     16#define TEST_PACKET_PID				0x0104
     17#define TEST_HS_HOST_PORT_SUSPEND_RESUME	0x0106
     18#define TEST_SINGLE_STEP_GET_DEV_DESC		0x0107
     19#define TEST_SINGLE_STEP_SET_FEATURE		0x0108
     20
     21extern const struct usb_device_id *usb_device_match_id(struct usb_device *udev,
     22						const struct usb_device_id *id);
     23
     24/*
     25 * A list of USB hubs which requires to disable the power
     26 * to the port before starting the testing procedures.
     27 */
     28static const struct usb_device_id ehset_hub_list[] = {
     29	{ USB_DEVICE(0x0424, 0x4502) },
     30	{ USB_DEVICE(0x0424, 0x4913) },
     31	{ USB_DEVICE(0x0451, 0x8027) },
     32	{ }
     33};
     34
     35static int ehset_prepare_port_for_testing(struct usb_device *hub_udev, u16 portnum)
     36{
     37	int ret = 0;
     38
     39	/*
     40	 * The USB2.0 spec chapter 11.24.2.13 says that the USB port which is
     41	 * going under test needs to be put in suspend before sending the
     42	 * test command. Most hubs don't enforce this precondition, but there
     43	 * are some hubs which needs to disable the power to the port before
     44	 * starting the test.
     45	 */
     46	if (usb_device_match_id(hub_udev, ehset_hub_list)) {
     47		ret = usb_control_msg_send(hub_udev, 0, USB_REQ_CLEAR_FEATURE,
     48					   USB_RT_PORT, USB_PORT_FEAT_ENABLE,
     49					   portnum, NULL, 0, 1000, GFP_KERNEL);
     50		/*
     51		 * Wait for the port to be disabled. It's an arbitrary value
     52		 * which worked every time.
     53		 */
     54		msleep(100);
     55	} else {
     56		/*
     57		 * For the hubs which are compliant with the spec,
     58		 * put the port in SUSPEND.
     59		 */
     60		ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
     61					   USB_RT_PORT, USB_PORT_FEAT_SUSPEND,
     62					   portnum, NULL, 0, 1000, GFP_KERNEL);
     63	}
     64	return ret;
     65}
     66
     67static int ehset_probe(struct usb_interface *intf,
     68		       const struct usb_device_id *id)
     69{
     70	int ret = -EINVAL;
     71	struct usb_device *dev = interface_to_usbdev(intf);
     72	struct usb_device *hub_udev = dev->parent;
     73	struct usb_device_descriptor buf;
     74	u8 portnum = dev->portnum;
     75	u16 test_pid = le16_to_cpu(dev->descriptor.idProduct);
     76
     77	switch (test_pid) {
     78	case TEST_SE0_NAK_PID:
     79		ret = ehset_prepare_port_for_testing(hub_udev, portnum);
     80		if (!ret)
     81			break;
     82		ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
     83					   USB_RT_PORT, USB_PORT_FEAT_TEST,
     84					   (USB_TEST_SE0_NAK << 8) | portnum,
     85					   NULL, 0, 1000, GFP_KERNEL);
     86		break;
     87	case TEST_J_PID:
     88		ret = ehset_prepare_port_for_testing(hub_udev, portnum);
     89		if (!ret)
     90			break;
     91		ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
     92					   USB_RT_PORT, USB_PORT_FEAT_TEST,
     93					   (USB_TEST_J << 8) | portnum, NULL, 0,
     94					   1000, GFP_KERNEL);
     95		break;
     96	case TEST_K_PID:
     97		ret = ehset_prepare_port_for_testing(hub_udev, portnum);
     98		if (!ret)
     99			break;
    100		ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
    101					   USB_RT_PORT, USB_PORT_FEAT_TEST,
    102					   (USB_TEST_K << 8) | portnum, NULL, 0,
    103					   1000, GFP_KERNEL);
    104		break;
    105	case TEST_PACKET_PID:
    106		ret = ehset_prepare_port_for_testing(hub_udev, portnum);
    107		if (!ret)
    108			break;
    109		ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
    110					   USB_RT_PORT, USB_PORT_FEAT_TEST,
    111					   (USB_TEST_PACKET << 8) | portnum,
    112					   NULL, 0, 1000, GFP_KERNEL);
    113		break;
    114	case TEST_HS_HOST_PORT_SUSPEND_RESUME:
    115		/* Test: wait for 15secs -> suspend -> 15secs delay -> resume */
    116		msleep(15 * 1000);
    117		ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
    118					   USB_RT_PORT, USB_PORT_FEAT_SUSPEND,
    119					   portnum, NULL, 0, 1000, GFP_KERNEL);
    120		if (ret < 0)
    121			break;
    122
    123		msleep(15 * 1000);
    124		ret = usb_control_msg_send(hub_udev, 0, USB_REQ_CLEAR_FEATURE,
    125					   USB_RT_PORT, USB_PORT_FEAT_SUSPEND,
    126					   portnum, NULL, 0, 1000, GFP_KERNEL);
    127		break;
    128	case TEST_SINGLE_STEP_GET_DEV_DESC:
    129		/* Test: wait for 15secs -> GetDescriptor request */
    130		msleep(15 * 1000);
    131
    132		ret = usb_control_msg_recv(dev, 0, USB_REQ_GET_DESCRIPTOR,
    133					   USB_DIR_IN, USB_DT_DEVICE << 8, 0,
    134					   &buf, USB_DT_DEVICE_SIZE,
    135					   USB_CTRL_GET_TIMEOUT, GFP_KERNEL);
    136		break;
    137	case TEST_SINGLE_STEP_SET_FEATURE:
    138		/*
    139		 * GetDescriptor SETUP request -> 15secs delay -> IN & STATUS
    140		 *
    141		 * Note, this test is only supported on root hubs since the
    142		 * SetPortFeature handling can only be done inside the HCD's
    143		 * hub_control callback function.
    144		 */
    145		if (hub_udev != dev->bus->root_hub) {
    146			dev_err(&intf->dev, "SINGLE_STEP_SET_FEATURE test only supported on root hub\n");
    147			break;
    148		}
    149
    150		ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
    151					   USB_RT_PORT, USB_PORT_FEAT_TEST,
    152					   (6 << 8) | portnum, NULL, 0,
    153					   60 * 1000, GFP_KERNEL);
    154
    155		break;
    156	default:
    157		dev_err(&intf->dev, "%s: unsupported PID: 0x%x\n",
    158			__func__, test_pid);
    159	}
    160
    161	return ret;
    162}
    163
    164static void ehset_disconnect(struct usb_interface *intf)
    165{
    166}
    167
    168static const struct usb_device_id ehset_id_table[] = {
    169	{ USB_DEVICE(0x1a0a, TEST_SE0_NAK_PID) },
    170	{ USB_DEVICE(0x1a0a, TEST_J_PID) },
    171	{ USB_DEVICE(0x1a0a, TEST_K_PID) },
    172	{ USB_DEVICE(0x1a0a, TEST_PACKET_PID) },
    173	{ USB_DEVICE(0x1a0a, TEST_HS_HOST_PORT_SUSPEND_RESUME) },
    174	{ USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_GET_DEV_DESC) },
    175	{ USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_SET_FEATURE) },
    176	{ }			/* Terminating entry */
    177};
    178MODULE_DEVICE_TABLE(usb, ehset_id_table);
    179
    180static struct usb_driver ehset_driver = {
    181	.name =		"usb_ehset_test",
    182	.probe =	ehset_probe,
    183	.disconnect =	ehset_disconnect,
    184	.id_table =	ehset_id_table,
    185};
    186
    187module_usb_driver(ehset_driver);
    188
    189MODULE_DESCRIPTION("USB Driver for EHSET Test Fixture");
    190MODULE_LICENSE("GPL v2");