linux/drivers/usb/misc/ehset.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 and
   6 * only version 2 as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 */
  13
  14#include <linux/kernel.h>
  15#include <linux/errno.h>
  16#include <linux/module.h>
  17#include <linux/slab.h>
  18#include <linux/usb.h>
  19#include <linux/usb/ch11.h>
  20
  21#define TEST_SE0_NAK_PID                        0x0101
  22#define TEST_J_PID                              0x0102
  23#define TEST_K_PID                              0x0103
  24#define TEST_PACKET_PID                         0x0104
  25#define TEST_HS_HOST_PORT_SUSPEND_RESUME        0x0106
  26#define TEST_SINGLE_STEP_GET_DEV_DESC           0x0107
  27#define TEST_SINGLE_STEP_SET_FEATURE            0x0108
  28
  29static int ehset_probe(struct usb_interface *intf,
  30                       const struct usb_device_id *id)
  31{
  32        int ret = -EINVAL;
  33        struct usb_device *dev = interface_to_usbdev(intf);
  34        struct usb_device *hub_udev = dev->parent;
  35        struct usb_device_descriptor *buf;
  36        u8 portnum = dev->portnum;
  37        u16 test_pid = le16_to_cpu(dev->descriptor.idProduct);
  38
  39        switch (test_pid) {
  40        case TEST_SE0_NAK_PID:
  41                ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
  42                                        USB_REQ_SET_FEATURE, USB_RT_PORT,
  43                                        USB_PORT_FEAT_TEST,
  44                                        (TEST_SE0_NAK << 8) | portnum,
  45                                        NULL, 0, 1000);
  46                break;
  47        case TEST_J_PID:
  48                ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
  49                                        USB_REQ_SET_FEATURE, USB_RT_PORT,
  50                                        USB_PORT_FEAT_TEST,
  51                                        (TEST_J << 8) | portnum,
  52                                        NULL, 0, 1000);
  53                break;
  54        case TEST_K_PID:
  55                ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
  56                                        USB_REQ_SET_FEATURE, USB_RT_PORT,
  57                                        USB_PORT_FEAT_TEST,
  58                                        (TEST_K << 8) | portnum,
  59                                        NULL, 0, 1000);
  60                break;
  61        case TEST_PACKET_PID:
  62                ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
  63                                        USB_REQ_SET_FEATURE, USB_RT_PORT,
  64                                        USB_PORT_FEAT_TEST,
  65                                        (TEST_PACKET << 8) | portnum,
  66                                        NULL, 0, 1000);
  67                break;
  68        case TEST_HS_HOST_PORT_SUSPEND_RESUME:
  69                /* Test: wait for 15secs -> suspend -> 15secs delay -> resume */
  70                msleep(15 * 1000);
  71                ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
  72                                        USB_REQ_SET_FEATURE, USB_RT_PORT,
  73                                        USB_PORT_FEAT_SUSPEND, portnum,
  74                                        NULL, 0, 1000);
  75                if (ret < 0)
  76                        break;
  77
  78                msleep(15 * 1000);
  79                ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
  80                                        USB_REQ_CLEAR_FEATURE, USB_RT_PORT,
  81                                        USB_PORT_FEAT_SUSPEND, portnum,
  82                                        NULL, 0, 1000);
  83                break;
  84        case TEST_SINGLE_STEP_GET_DEV_DESC:
  85                /* Test: wait for 15secs -> GetDescriptor request */
  86                msleep(15 * 1000);
  87                buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
  88                if (!buf)
  89                        return -ENOMEM;
  90
  91                ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
  92                                        USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
  93                                        USB_DT_DEVICE << 8, 0,
  94                                        buf, USB_DT_DEVICE_SIZE,
  95                                        USB_CTRL_GET_TIMEOUT);
  96                kfree(buf);
  97                break;
  98        case TEST_SINGLE_STEP_SET_FEATURE:
  99                /*
 100                 * GetDescriptor SETUP request -> 15secs delay -> IN & STATUS
 101                 *
 102                 * Note, this test is only supported on root hubs since the
 103                 * SetPortFeature handling can only be done inside the HCD's
 104                 * hub_control callback function.
 105                 */
 106                if (hub_udev != dev->bus->root_hub) {
 107                        dev_err(&intf->dev, "SINGLE_STEP_SET_FEATURE test only supported on root hub\n");
 108                        break;
 109                }
 110
 111                ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
 112                                        USB_REQ_SET_FEATURE, USB_RT_PORT,
 113                                        USB_PORT_FEAT_TEST,
 114                                        (6 << 8) | portnum,
 115                                        NULL, 0, 60 * 1000);
 116
 117                break;
 118        default:
 119                dev_err(&intf->dev, "%s: unsupported PID: 0x%x\n",
 120                        __func__, test_pid);
 121        }
 122
 123        return (ret < 0) ? ret : 0;
 124}
 125
 126static void ehset_disconnect(struct usb_interface *intf)
 127{
 128}
 129
 130static const struct usb_device_id ehset_id_table[] = {
 131        { USB_DEVICE(0x1a0a, TEST_SE0_NAK_PID) },
 132        { USB_DEVICE(0x1a0a, TEST_J_PID) },
 133        { USB_DEVICE(0x1a0a, TEST_K_PID) },
 134        { USB_DEVICE(0x1a0a, TEST_PACKET_PID) },
 135        { USB_DEVICE(0x1a0a, TEST_HS_HOST_PORT_SUSPEND_RESUME) },
 136        { USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_GET_DEV_DESC) },
 137        { USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_SET_FEATURE) },
 138        { }                     /* Terminating entry */
 139};
 140MODULE_DEVICE_TABLE(usb, ehset_id_table);
 141
 142static struct usb_driver ehset_driver = {
 143        .name =         "usb_ehset_test",
 144        .probe =        ehset_probe,
 145        .disconnect =   ehset_disconnect,
 146        .id_table =     ehset_id_table,
 147};
 148
 149module_usb_driver(ehset_driver);
 150
 151MODULE_DESCRIPTION("USB Driver for EHSET Test Fixture");
 152MODULE_LICENSE("GPL v2");
 153