root/drivers/usb/misc/lvstest.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. create_lvs_device
  2. destroy_lvs_device
  3. lvs_rh_clear_port_feature
  4. lvs_rh_set_port_feature
  5. u3_entry_store
  6. u3_exit_store
  7. hot_reset_store
  8. warm_reset_store
  9. u2_timeout_store
  10. u1_timeout_store
  11. get_dev_desc_store
  12. enable_compliance_store
  13. lvs_rh_work
  14. lvs_rh_irq
  15. lvs_rh_probe
  16. lvs_rh_disconnect

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * drivers/usb/misc/lvstest.c
   4  *
   5  * Test pattern generation for Link Layer Validation System Tests
   6  *
   7  * Copyright (C) 2014 ST Microelectronics
   8  * Pratyush Anand <pratyush.anand@gmail.com>
   9  */
  10 
  11 #include <linux/init.h>
  12 #include <linux/kernel.h>
  13 #include <linux/module.h>
  14 #include <linux/platform_device.h>
  15 #include <linux/slab.h>
  16 #include <linux/usb.h>
  17 #include <linux/usb/ch11.h>
  18 #include <linux/usb/hcd.h>
  19 #include <linux/usb/phy.h>
  20 
  21 struct lvs_rh {
  22         /* root hub interface */
  23         struct usb_interface *intf;
  24         /* if lvs device connected */
  25         bool present;
  26         /* port no at which lvs device is present */
  27         int portnum;
  28         /* urb buffer */
  29         u8 buffer[8];
  30         /* class descriptor */
  31         struct usb_hub_descriptor descriptor;
  32         /* urb for polling interrupt pipe */
  33         struct urb *urb;
  34         /* LVH RH work */
  35         struct work_struct      rh_work;
  36         /* RH port status */
  37         struct usb_port_status port_status;
  38 };
  39 
  40 static struct usb_device *create_lvs_device(struct usb_interface *intf)
  41 {
  42         struct usb_device *udev, *hdev;
  43         struct usb_hcd *hcd;
  44         struct lvs_rh *lvs = usb_get_intfdata(intf);
  45 
  46         if (!lvs->present) {
  47                 dev_err(&intf->dev, "No LVS device is present\n");
  48                 return NULL;
  49         }
  50 
  51         hdev = interface_to_usbdev(intf);
  52         hcd = bus_to_hcd(hdev->bus);
  53 
  54         udev = usb_alloc_dev(hdev, hdev->bus, lvs->portnum);
  55         if (!udev) {
  56                 dev_err(&intf->dev, "Could not allocate lvs udev\n");
  57                 return NULL;
  58         }
  59         udev->speed = USB_SPEED_SUPER;
  60         udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
  61         usb_set_device_state(udev, USB_STATE_DEFAULT);
  62 
  63         if (hcd->driver->enable_device) {
  64                 if (hcd->driver->enable_device(hcd, udev) < 0) {
  65                         dev_err(&intf->dev, "Failed to enable\n");
  66                         usb_put_dev(udev);
  67                         return NULL;
  68                 }
  69         }
  70 
  71         return udev;
  72 }
  73 
  74 static void destroy_lvs_device(struct usb_device *udev)
  75 {
  76         struct usb_device *hdev = udev->parent;
  77         struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
  78 
  79         if (hcd->driver->free_dev)
  80                 hcd->driver->free_dev(hcd, udev);
  81 
  82         usb_put_dev(udev);
  83 }
  84 
  85 static int lvs_rh_clear_port_feature(struct usb_device *hdev,
  86                 int port1, int feature)
  87 {
  88         return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
  89                 USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1,
  90                 NULL, 0, 1000);
  91 }
  92 
  93 static int lvs_rh_set_port_feature(struct usb_device *hdev,
  94                 int port1, int feature)
  95 {
  96         return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
  97                 USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1,
  98                 NULL, 0, 1000);
  99 }
 100 
 101 static ssize_t u3_entry_store(struct device *dev,
 102                 struct device_attribute *attr, const char *buf, size_t count)
 103 {
 104         struct usb_interface *intf = to_usb_interface(dev);
 105         struct usb_device *hdev = interface_to_usbdev(intf);
 106         struct lvs_rh *lvs = usb_get_intfdata(intf);
 107         struct usb_device *udev;
 108         int ret;
 109 
 110         udev = create_lvs_device(intf);
 111         if (!udev) {
 112                 dev_err(dev, "failed to create lvs device\n");
 113                 return -ENOMEM;
 114         }
 115 
 116         ret = lvs_rh_set_port_feature(hdev, lvs->portnum,
 117                         USB_PORT_FEAT_SUSPEND);
 118         if (ret < 0)
 119                 dev_err(dev, "can't issue U3 entry %d\n", ret);
 120 
 121         destroy_lvs_device(udev);
 122 
 123         if (ret < 0)
 124                 return ret;
 125 
 126         return count;
 127 }
 128 static DEVICE_ATTR_WO(u3_entry);
 129 
 130 static ssize_t u3_exit_store(struct device *dev,
 131                 struct device_attribute *attr, const char *buf, size_t count)
 132 {
 133         struct usb_interface *intf = to_usb_interface(dev);
 134         struct usb_device *hdev = interface_to_usbdev(intf);
 135         struct lvs_rh *lvs = usb_get_intfdata(intf);
 136         struct usb_device *udev;
 137         int ret;
 138 
 139         udev = create_lvs_device(intf);
 140         if (!udev) {
 141                 dev_err(dev, "failed to create lvs device\n");
 142                 return -ENOMEM;
 143         }
 144 
 145         ret = lvs_rh_clear_port_feature(hdev, lvs->portnum,
 146                         USB_PORT_FEAT_SUSPEND);
 147         if (ret < 0)
 148                 dev_err(dev, "can't issue U3 exit %d\n", ret);
 149 
 150         destroy_lvs_device(udev);
 151 
 152         if (ret < 0)
 153                 return ret;
 154 
 155         return count;
 156 }
 157 static DEVICE_ATTR_WO(u3_exit);
 158 
 159 static ssize_t hot_reset_store(struct device *dev,
 160                 struct device_attribute *attr, const char *buf, size_t count)
 161 {
 162         struct usb_interface *intf = to_usb_interface(dev);
 163         struct usb_device *hdev = interface_to_usbdev(intf);
 164         struct lvs_rh *lvs = usb_get_intfdata(intf);
 165         int ret;
 166 
 167         ret = lvs_rh_set_port_feature(hdev, lvs->portnum,
 168                         USB_PORT_FEAT_RESET);
 169         if (ret < 0) {
 170                 dev_err(dev, "can't issue hot reset %d\n", ret);
 171                 return ret;
 172         }
 173 
 174         return count;
 175 }
 176 static DEVICE_ATTR_WO(hot_reset);
 177 
 178 static ssize_t warm_reset_store(struct device *dev,
 179                 struct device_attribute *attr, const char *buf, size_t count)
 180 {
 181         struct usb_interface *intf = to_usb_interface(dev);
 182         struct usb_device *hdev = interface_to_usbdev(intf);
 183         struct lvs_rh *lvs = usb_get_intfdata(intf);
 184         int ret;
 185 
 186         ret = lvs_rh_set_port_feature(hdev, lvs->portnum,
 187                         USB_PORT_FEAT_BH_PORT_RESET);
 188         if (ret < 0) {
 189                 dev_err(dev, "can't issue warm reset %d\n", ret);
 190                 return ret;
 191         }
 192 
 193         return count;
 194 }
 195 static DEVICE_ATTR_WO(warm_reset);
 196 
 197 static ssize_t u2_timeout_store(struct device *dev,
 198                 struct device_attribute *attr, const char *buf, size_t count)
 199 {
 200         struct usb_interface *intf = to_usb_interface(dev);
 201         struct usb_device *hdev = interface_to_usbdev(intf);
 202         struct lvs_rh *lvs = usb_get_intfdata(intf);
 203         unsigned long val;
 204         int ret;
 205 
 206         ret = kstrtoul(buf, 10, &val);
 207         if (ret < 0) {
 208                 dev_err(dev, "couldn't parse string %d\n", ret);
 209                 return ret;
 210         }
 211 
 212         if (val > 127)
 213                 return -EINVAL;
 214 
 215         ret = lvs_rh_set_port_feature(hdev, lvs->portnum | (val << 8),
 216                         USB_PORT_FEAT_U2_TIMEOUT);
 217         if (ret < 0) {
 218                 dev_err(dev, "Error %d while setting U2 timeout %ld\n", ret, val);
 219                 return ret;
 220         }
 221 
 222         return count;
 223 }
 224 static DEVICE_ATTR_WO(u2_timeout);
 225 
 226 static ssize_t u1_timeout_store(struct device *dev,
 227                 struct device_attribute *attr, const char *buf, size_t count)
 228 {
 229         struct usb_interface *intf = to_usb_interface(dev);
 230         struct usb_device *hdev = interface_to_usbdev(intf);
 231         struct lvs_rh *lvs = usb_get_intfdata(intf);
 232         unsigned long val;
 233         int ret;
 234 
 235         ret = kstrtoul(buf, 10, &val);
 236         if (ret < 0) {
 237                 dev_err(dev, "couldn't parse string %d\n", ret);
 238                 return ret;
 239         }
 240 
 241         if (val > 127)
 242                 return -EINVAL;
 243 
 244         ret = lvs_rh_set_port_feature(hdev, lvs->portnum | (val << 8),
 245                         USB_PORT_FEAT_U1_TIMEOUT);
 246         if (ret < 0) {
 247                 dev_err(dev, "Error %d while setting U1 timeout %ld\n", ret, val);
 248                 return ret;
 249         }
 250 
 251         return count;
 252 }
 253 static DEVICE_ATTR_WO(u1_timeout);
 254 
 255 static ssize_t get_dev_desc_store(struct device *dev,
 256                 struct device_attribute *attr, const char *buf, size_t count)
 257 {
 258         struct usb_interface *intf = to_usb_interface(dev);
 259         struct usb_device *udev;
 260         struct usb_device_descriptor *descriptor;
 261         int ret;
 262 
 263         descriptor = kmalloc(sizeof(*descriptor), GFP_KERNEL);
 264         if (!descriptor)
 265                 return -ENOMEM;
 266 
 267         udev = create_lvs_device(intf);
 268         if (!udev) {
 269                 dev_err(dev, "failed to create lvs device\n");
 270                 ret = -ENOMEM;
 271                 goto free_desc;
 272         }
 273 
 274         ret = usb_control_msg(udev, (PIPE_CONTROL << 30) | USB_DIR_IN,
 275                         USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, USB_DT_DEVICE << 8,
 276                         0, descriptor, sizeof(*descriptor),
 277                         USB_CTRL_GET_TIMEOUT);
 278         if (ret < 0)
 279                 dev_err(dev, "can't read device descriptor %d\n", ret);
 280 
 281         destroy_lvs_device(udev);
 282 
 283 free_desc:
 284         kfree(descriptor);
 285 
 286         if (ret < 0)
 287                 return ret;
 288 
 289         return count;
 290 }
 291 static DEVICE_ATTR_WO(get_dev_desc);
 292 
 293 static ssize_t enable_compliance_store(struct device *dev,
 294                 struct device_attribute *attr, const char *buf, size_t count)
 295 {
 296         struct usb_interface *intf = to_usb_interface(dev);
 297         struct usb_device *hdev = interface_to_usbdev(intf);
 298         struct lvs_rh *lvs = usb_get_intfdata(intf);
 299         int ret;
 300 
 301         ret = lvs_rh_set_port_feature(hdev,
 302                         lvs->portnum | USB_SS_PORT_LS_COMP_MOD << 3,
 303                         USB_PORT_FEAT_LINK_STATE);
 304         if (ret < 0) {
 305                 dev_err(dev, "can't enable compliance mode %d\n", ret);
 306                 return ret;
 307         }
 308 
 309         return count;
 310 }
 311 static DEVICE_ATTR_WO(enable_compliance);
 312 
 313 static struct attribute *lvs_attrs[] = {
 314         &dev_attr_get_dev_desc.attr,
 315         &dev_attr_u1_timeout.attr,
 316         &dev_attr_u2_timeout.attr,
 317         &dev_attr_hot_reset.attr,
 318         &dev_attr_warm_reset.attr,
 319         &dev_attr_u3_entry.attr,
 320         &dev_attr_u3_exit.attr,
 321         &dev_attr_enable_compliance.attr,
 322         NULL
 323 };
 324 ATTRIBUTE_GROUPS(lvs);
 325 
 326 static void lvs_rh_work(struct work_struct *work)
 327 {
 328         struct lvs_rh *lvs = container_of(work, struct lvs_rh, rh_work);
 329         struct usb_interface *intf = lvs->intf;
 330         struct usb_device *hdev = interface_to_usbdev(intf);
 331         struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
 332         struct usb_hub_descriptor *descriptor = &lvs->descriptor;
 333         struct usb_port_status *port_status = &lvs->port_status;
 334         int i, ret = 0;
 335         u16 portchange;
 336 
 337         /* Examine each root port */
 338         for (i = 1; i <= descriptor->bNbrPorts; i++) {
 339                 ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
 340                         USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, i,
 341                         port_status, sizeof(*port_status), 1000);
 342                 if (ret < 4)
 343                         continue;
 344 
 345                 portchange = le16_to_cpu(port_status->wPortChange);
 346 
 347                 if (portchange & USB_PORT_STAT_C_LINK_STATE)
 348                         lvs_rh_clear_port_feature(hdev, i,
 349                                         USB_PORT_FEAT_C_PORT_LINK_STATE);
 350                 if (portchange & USB_PORT_STAT_C_ENABLE)
 351                         lvs_rh_clear_port_feature(hdev, i,
 352                                         USB_PORT_FEAT_C_ENABLE);
 353                 if (portchange & USB_PORT_STAT_C_RESET)
 354                         lvs_rh_clear_port_feature(hdev, i,
 355                                         USB_PORT_FEAT_C_RESET);
 356                 if (portchange & USB_PORT_STAT_C_BH_RESET)
 357                         lvs_rh_clear_port_feature(hdev, i,
 358                                         USB_PORT_FEAT_C_BH_PORT_RESET);
 359                 if (portchange & USB_PORT_STAT_C_CONNECTION) {
 360                         lvs_rh_clear_port_feature(hdev, i,
 361                                         USB_PORT_FEAT_C_CONNECTION);
 362 
 363                         if (le16_to_cpu(port_status->wPortStatus) &
 364                                         USB_PORT_STAT_CONNECTION) {
 365                                 lvs->present = true;
 366                                 lvs->portnum = i;
 367                                 if (hcd->usb_phy)
 368                                         usb_phy_notify_connect(hcd->usb_phy,
 369                                                         USB_SPEED_SUPER);
 370                         } else {
 371                                 lvs->present = false;
 372                                 if (hcd->usb_phy)
 373                                         usb_phy_notify_disconnect(hcd->usb_phy,
 374                                                         USB_SPEED_SUPER);
 375                         }
 376                         break;
 377                 }
 378         }
 379 
 380         ret = usb_submit_urb(lvs->urb, GFP_KERNEL);
 381         if (ret != 0 && ret != -ENODEV && ret != -EPERM)
 382                 dev_err(&intf->dev, "urb resubmit error %d\n", ret);
 383 }
 384 
 385 static void lvs_rh_irq(struct urb *urb)
 386 {
 387         struct lvs_rh *lvs = urb->context;
 388 
 389         schedule_work(&lvs->rh_work);
 390 }
 391 
 392 static int lvs_rh_probe(struct usb_interface *intf,
 393                 const struct usb_device_id *id)
 394 {
 395         struct usb_device *hdev;
 396         struct usb_host_interface *desc;
 397         struct usb_endpoint_descriptor *endpoint;
 398         struct lvs_rh *lvs;
 399         unsigned int pipe;
 400         int ret, maxp;
 401 
 402         hdev = interface_to_usbdev(intf);
 403         desc = intf->cur_altsetting;
 404 
 405         ret = usb_find_int_in_endpoint(desc, &endpoint);
 406         if (ret)
 407                 return ret;
 408 
 409         /* valid only for SS root hub */
 410         if (hdev->descriptor.bDeviceProtocol != USB_HUB_PR_SS || hdev->parent) {
 411                 dev_err(&intf->dev, "Bind LVS driver with SS root Hub only\n");
 412                 return -EINVAL;
 413         }
 414 
 415         lvs = devm_kzalloc(&intf->dev, sizeof(*lvs), GFP_KERNEL);
 416         if (!lvs)
 417                 return -ENOMEM;
 418 
 419         lvs->intf = intf;
 420         usb_set_intfdata(intf, lvs);
 421 
 422         /* how many number of ports this root hub has */
 423         ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
 424                         USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
 425                         USB_DT_SS_HUB << 8, 0, &lvs->descriptor,
 426                         USB_DT_SS_HUB_SIZE, USB_CTRL_GET_TIMEOUT);
 427         if (ret < (USB_DT_HUB_NONVAR_SIZE + 2)) {
 428                 dev_err(&hdev->dev, "wrong root hub descriptor read %d\n", ret);
 429                 return ret;
 430         }
 431 
 432         /* submit urb to poll interrupt endpoint */
 433         lvs->urb = usb_alloc_urb(0, GFP_KERNEL);
 434         if (!lvs->urb)
 435                 return -ENOMEM;
 436 
 437         INIT_WORK(&lvs->rh_work, lvs_rh_work);
 438 
 439         pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);
 440         maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));
 441         usb_fill_int_urb(lvs->urb, hdev, pipe, &lvs->buffer[0], maxp,
 442                         lvs_rh_irq, lvs, endpoint->bInterval);
 443 
 444         ret = usb_submit_urb(lvs->urb, GFP_KERNEL);
 445         if (ret < 0) {
 446                 dev_err(&intf->dev, "couldn't submit lvs urb %d\n", ret);
 447                 goto free_urb;
 448         }
 449 
 450         return ret;
 451 
 452 free_urb:
 453         usb_free_urb(lvs->urb);
 454         return ret;
 455 }
 456 
 457 static void lvs_rh_disconnect(struct usb_interface *intf)
 458 {
 459         struct lvs_rh *lvs = usb_get_intfdata(intf);
 460 
 461         usb_poison_urb(lvs->urb); /* used in scheduled work */
 462         flush_work(&lvs->rh_work);
 463         usb_free_urb(lvs->urb);
 464 }
 465 
 466 static struct usb_driver lvs_driver = {
 467         .name =         "lvs",
 468         .probe =        lvs_rh_probe,
 469         .disconnect =   lvs_rh_disconnect,
 470         .dev_groups =   lvs_groups,
 471 };
 472 
 473 module_usb_driver(lvs_driver);
 474 
 475 MODULE_DESCRIPTION("Link Layer Validation System Driver");
 476 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */