Commit b62dabfb authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'usb-4.6-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB driver fixes from Greg KH:
 "Here are some small USB fixes for 4.6-rc4.

  Mostly xhci fixes for reported issues, a UAS bug that has hit a number
  of people, including stable tree users, and a few other minor things.

  All have been in linux-next for a while with no reported issues"

* tag 'usb-4.6-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  usb: hcd: out of bounds access in for_each_companion
  USB: uas: Add a new NO_REPORT_LUNS quirk
  USB: uas: Limit qdepth at the scsi-host level
  doc: usb: Fix typo in gadget_multi documentation
  usb: host: xhci-plat: Make enum xhci_plat_type start at a non zero value
  xhci: fix 10 second timeout on removal of PCI hotpluggable xhci controllers
  usb: xhci: fix wild pointers in xhci_mem_cleanup
  usb: host: xhci-plat: fix cannot work if R-Car Gen2/3 run on above 4GB phys
  usb: host: xhci: add a new quirk XHCI_NO_64BIT_SUPPORT
  xhci: resume USB 3 roothub first
  usb: xhci: applying XHCI_PME_STUCK_QUIRK to Intel BXT B0 host
  cdc-acm: fix crash if flushed with nothing buffered
parents 306a63be e86103a7
...@@ -4077,6 +4077,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -4077,6 +4077,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
sector if the number is odd); sector if the number is odd);
i = IGNORE_DEVICE (don't bind to this i = IGNORE_DEVICE (don't bind to this
device); device);
j = NO_REPORT_LUNS (don't use report luns
command, uas only);
l = NOT_LOCKABLE (don't try to lock and l = NOT_LOCKABLE (don't try to lock and
unlock ejectable media); unlock ejectable media);
m = MAX_SECTORS_64 (don't transfer more m = MAX_SECTORS_64 (don't transfer more
......
...@@ -43,7 +43,7 @@ For the gadget two work under Windows two conditions have to be met: ...@@ -43,7 +43,7 @@ For the gadget two work under Windows two conditions have to be met:
First of all, Windows need to detect the gadget as an USB composite First of all, Windows need to detect the gadget as an USB composite
gadget which on its own have some conditions[4]. If they are met, gadget which on its own have some conditions[4]. If they are met,
Windows lets USB Generic Parent Driver[5] handle the device which then Windows lets USB Generic Parent Driver[5] handle the device which then
tries to much drivers for each individual interface (sort of, don't tries to match drivers for each individual interface (sort of, don't
get into too many details). get into too many details).
The good news is: you do not have to worry about most of the The good news is: you do not have to worry about most of the
......
...@@ -744,11 +744,15 @@ static void acm_tty_flush_chars(struct tty_struct *tty) ...@@ -744,11 +744,15 @@ static void acm_tty_flush_chars(struct tty_struct *tty)
int err; int err;
unsigned long flags; unsigned long flags;
if (!cur) /* nothing to do */
return;
acm->putbuffer = NULL; acm->putbuffer = NULL;
err = usb_autopm_get_interface_async(acm->control); err = usb_autopm_get_interface_async(acm->control);
spin_lock_irqsave(&acm->write_lock, flags); spin_lock_irqsave(&acm->write_lock, flags);
if (err < 0) { if (err < 0) {
cur->use = 0; cur->use = 0;
acm->putbuffer = cur;
goto out; goto out;
} }
......
...@@ -73,6 +73,15 @@ static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd, ...@@ -73,6 +73,15 @@ static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd,
if (companion->bus != pdev->bus || if (companion->bus != pdev->bus ||
PCI_SLOT(companion->devfn) != slot) PCI_SLOT(companion->devfn) != slot)
continue; continue;
/*
* Companion device should be either UHCI,OHCI or EHCI host
* controller, otherwise skip.
*/
if (companion->class != CL_UHCI && companion->class != CL_OHCI &&
companion->class != CL_EHCI)
continue;
companion_hcd = pci_get_drvdata(companion); companion_hcd = pci_get_drvdata(companion);
if (!companion_hcd || !companion_hcd->self.root_hub) if (!companion_hcd || !companion_hcd->self.root_hub)
continue; continue;
......
...@@ -1861,6 +1861,12 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) ...@@ -1861,6 +1861,12 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
kfree(xhci->rh_bw); kfree(xhci->rh_bw);
kfree(xhci->ext_caps); kfree(xhci->ext_caps);
xhci->usb2_ports = NULL;
xhci->usb3_ports = NULL;
xhci->port_array = NULL;
xhci->rh_bw = NULL;
xhci->ext_caps = NULL;
xhci->page_size = 0; xhci->page_size = 0;
xhci->page_shift = 0; xhci->page_shift = 0;
xhci->bus_state[0].bus_suspended = 0; xhci->bus_state[0].bus_suspended = 0;
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI 0xa12f #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI 0xa12f
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI 0x9d2f #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI 0x9d2f
#define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI 0x0aa8 #define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI 0x0aa8
#define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI 0x1aa8
static const char hcd_name[] = "xhci_hcd"; static const char hcd_name[] = "xhci_hcd";
...@@ -155,7 +156,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) ...@@ -155,7 +156,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
(pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || (pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI)) { pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI)) {
xhci->quirks |= XHCI_PME_STUCK_QUIRK; xhci->quirks |= XHCI_PME_STUCK_QUIRK;
} }
if (pdev->vendor == PCI_VENDOR_ID_INTEL && if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
...@@ -302,6 +304,7 @@ static void xhci_pci_remove(struct pci_dev *dev) ...@@ -302,6 +304,7 @@ static void xhci_pci_remove(struct pci_dev *dev)
struct xhci_hcd *xhci; struct xhci_hcd *xhci;
xhci = hcd_to_xhci(pci_get_drvdata(dev)); xhci = hcd_to_xhci(pci_get_drvdata(dev));
xhci->xhc_state |= XHCI_STATE_REMOVING;
if (xhci->shared_hcd) { if (xhci->shared_hcd) {
usb_remove_hcd(xhci->shared_hcd); usb_remove_hcd(xhci->shared_hcd);
usb_put_hcd(xhci->shared_hcd); usb_put_hcd(xhci->shared_hcd);
......
...@@ -39,12 +39,25 @@ static const struct xhci_driver_overrides xhci_plat_overrides __initconst = { ...@@ -39,12 +39,25 @@ static const struct xhci_driver_overrides xhci_plat_overrides __initconst = {
static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
{ {
struct usb_hcd *hcd = xhci_to_hcd(xhci);
/* /*
* As of now platform drivers don't provide MSI support so we ensure * As of now platform drivers don't provide MSI support so we ensure
* here that the generic code does not try to make a pci_dev from our * here that the generic code does not try to make a pci_dev from our
* dev struct in order to setup MSI * dev struct in order to setup MSI
*/ */
xhci->quirks |= XHCI_PLAT; xhci->quirks |= XHCI_PLAT;
/*
* On R-Car Gen2 and Gen3, the AC64 bit (bit 0) of HCCPARAMS1 is set
* to 1. However, these SoCs don't support 64-bit address memory
* pointers. So, this driver clears the AC64 bit of xhci->hcc_params
* to call dma_set_coherent_mask(dev, DMA_BIT_MASK(32)) in
* xhci_gen_setup().
*/
if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2) ||
xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3))
xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
} }
/* called during probe() after chip reset completes */ /* called during probe() after chip reset completes */
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include "xhci.h" /* for hcd_to_xhci() */ #include "xhci.h" /* for hcd_to_xhci() */
enum xhci_plat_type { enum xhci_plat_type {
XHCI_PLAT_TYPE_MARVELL_ARMADA, XHCI_PLAT_TYPE_MARVELL_ARMADA = 1,
XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2,
XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3,
}; };
......
...@@ -4004,7 +4004,8 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd, ...@@ -4004,7 +4004,8 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd,
int reserved_trbs = xhci->cmd_ring_reserved_trbs; int reserved_trbs = xhci->cmd_ring_reserved_trbs;
int ret; int ret;
if (xhci->xhc_state) { if ((xhci->xhc_state & XHCI_STATE_DYING) ||
(xhci->xhc_state & XHCI_STATE_HALTED)) {
xhci_dbg(xhci, "xHCI dying or halted, can't queue_command\n"); xhci_dbg(xhci, "xHCI dying or halted, can't queue_command\n");
return -ESHUTDOWN; return -ESHUTDOWN;
} }
......
...@@ -147,7 +147,8 @@ static int xhci_start(struct xhci_hcd *xhci) ...@@ -147,7 +147,8 @@ static int xhci_start(struct xhci_hcd *xhci)
"waited %u microseconds.\n", "waited %u microseconds.\n",
XHCI_MAX_HALT_USEC); XHCI_MAX_HALT_USEC);
if (!ret) if (!ret)
xhci->xhc_state &= ~(XHCI_STATE_HALTED | XHCI_STATE_DYING); /* clear state flags. Including dying, halted or removing */
xhci->xhc_state = 0;
return ret; return ret;
} }
...@@ -1108,8 +1109,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) ...@@ -1108,8 +1109,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
/* Resume root hubs only when have pending events. */ /* Resume root hubs only when have pending events. */
status = readl(&xhci->op_regs->status); status = readl(&xhci->op_regs->status);
if (status & STS_EINT) { if (status & STS_EINT) {
usb_hcd_resume_root_hub(hcd);
usb_hcd_resume_root_hub(xhci->shared_hcd); usb_hcd_resume_root_hub(xhci->shared_hcd);
usb_hcd_resume_root_hub(hcd);
} }
} }
...@@ -1124,10 +1125,10 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) ...@@ -1124,10 +1125,10 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
/* Re-enable port polling. */ /* Re-enable port polling. */
xhci_dbg(xhci, "%s: starting port polling.\n", __func__); xhci_dbg(xhci, "%s: starting port polling.\n", __func__);
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
usb_hcd_poll_rh_status(hcd);
set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
usb_hcd_poll_rh_status(xhci->shared_hcd); usb_hcd_poll_rh_status(xhci->shared_hcd);
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
usb_hcd_poll_rh_status(hcd);
return retval; return retval;
} }
...@@ -2773,7 +2774,8 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) ...@@ -2773,7 +2774,8 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
if (ret <= 0) if (ret <= 0)
return ret; return ret;
xhci = hcd_to_xhci(hcd); xhci = hcd_to_xhci(hcd);
if (xhci->xhc_state & XHCI_STATE_DYING) if ((xhci->xhc_state & XHCI_STATE_DYING) ||
(xhci->xhc_state & XHCI_STATE_REMOVING))
return -ENODEV; return -ENODEV;
xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev); xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
...@@ -3820,7 +3822,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, ...@@ -3820,7 +3822,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
mutex_lock(&xhci->mutex); mutex_lock(&xhci->mutex);
if (xhci->xhc_state) /* dying or halted */ if (xhci->xhc_state) /* dying, removing or halted */
goto out; goto out;
if (!udev->slot_id) { if (!udev->slot_id) {
...@@ -4948,6 +4950,16 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) ...@@ -4948,6 +4950,16 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
return retval; return retval;
xhci_dbg(xhci, "Reset complete\n"); xhci_dbg(xhci, "Reset complete\n");
/*
* On some xHCI controllers (e.g. R-Car SoCs), the AC64 bit (bit 0)
* of HCCPARAMS1 is set to 1. However, the xHCs don't support 64-bit
* address memory pointers actually. So, this driver clears the AC64
* bit of xhci->hcc_params to call dma_set_coherent_mask(dev,
* DMA_BIT_MASK(32)) in this xhci_gen_setup().
*/
if (xhci->quirks & XHCI_NO_64BIT_SUPPORT)
xhci->hcc_params &= ~BIT(0);
/* Set dma_mask and coherent_dma_mask to 64-bits, /* Set dma_mask and coherent_dma_mask to 64-bits,
* if xHC supports 64-bit addressing */ * if xHC supports 64-bit addressing */
if (HCC_64BIT_ADDR(xhci->hcc_params) && if (HCC_64BIT_ADDR(xhci->hcc_params) &&
......
...@@ -1605,6 +1605,7 @@ struct xhci_hcd { ...@@ -1605,6 +1605,7 @@ struct xhci_hcd {
*/ */
#define XHCI_STATE_DYING (1 << 0) #define XHCI_STATE_DYING (1 << 0)
#define XHCI_STATE_HALTED (1 << 1) #define XHCI_STATE_HALTED (1 << 1)
#define XHCI_STATE_REMOVING (1 << 2)
/* Statistics */ /* Statistics */
int error_bitmask; int error_bitmask;
unsigned int quirks; unsigned int quirks;
...@@ -1641,6 +1642,7 @@ struct xhci_hcd { ...@@ -1641,6 +1642,7 @@ struct xhci_hcd {
#define XHCI_PME_STUCK_QUIRK (1 << 20) #define XHCI_PME_STUCK_QUIRK (1 << 20)
#define XHCI_MTK_HOST (1 << 21) #define XHCI_MTK_HOST (1 << 21)
#define XHCI_SSIC_PORT_UNUSED (1 << 22) #define XHCI_SSIC_PORT_UNUSED (1 << 22)
#define XHCI_NO_64BIT_SUPPORT (1 << 23)
unsigned int num_active_eps; unsigned int num_active_eps;
unsigned int limit_active_eps; unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */ /* There are two roothubs to keep track of bus suspend info for */
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* USB Attached SCSI * USB Attached SCSI
* Note that this is not the same as the USB Mass Storage driver * Note that this is not the same as the USB Mass Storage driver
* *
* Copyright Hans de Goede <hdegoede@redhat.com> for Red Hat, Inc. 2013 - 2014 * Copyright Hans de Goede <hdegoede@redhat.com> for Red Hat, Inc. 2013 - 2016
* Copyright Matthew Wilcox for Intel Corp, 2010 * Copyright Matthew Wilcox for Intel Corp, 2010
* Copyright Sarah Sharp for Intel Corp, 2010 * Copyright Sarah Sharp for Intel Corp, 2010
* *
...@@ -781,6 +781,17 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd) ...@@ -781,6 +781,17 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
return SUCCESS; return SUCCESS;
} }
static int uas_target_alloc(struct scsi_target *starget)
{
struct uas_dev_info *devinfo = (struct uas_dev_info *)
dev_to_shost(starget->dev.parent)->hostdata;
if (devinfo->flags & US_FL_NO_REPORT_LUNS)
starget->no_report_luns = 1;
return 0;
}
static int uas_slave_alloc(struct scsi_device *sdev) static int uas_slave_alloc(struct scsi_device *sdev)
{ {
struct uas_dev_info *devinfo = struct uas_dev_info *devinfo =
...@@ -824,7 +835,6 @@ static int uas_slave_configure(struct scsi_device *sdev) ...@@ -824,7 +835,6 @@ static int uas_slave_configure(struct scsi_device *sdev)
if (devinfo->flags & US_FL_BROKEN_FUA) if (devinfo->flags & US_FL_BROKEN_FUA)
sdev->broken_fua = 1; sdev->broken_fua = 1;
scsi_change_queue_depth(sdev, devinfo->qdepth - 2);
return 0; return 0;
} }
...@@ -832,6 +842,7 @@ static struct scsi_host_template uas_host_template = { ...@@ -832,6 +842,7 @@ static struct scsi_host_template uas_host_template = {
.module = THIS_MODULE, .module = THIS_MODULE,
.name = "uas", .name = "uas",
.queuecommand = uas_queuecommand, .queuecommand = uas_queuecommand,
.target_alloc = uas_target_alloc,
.slave_alloc = uas_slave_alloc, .slave_alloc = uas_slave_alloc,
.slave_configure = uas_slave_configure, .slave_configure = uas_slave_configure,
.eh_abort_handler = uas_eh_abort_handler, .eh_abort_handler = uas_eh_abort_handler,
...@@ -956,6 +967,12 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -956,6 +967,12 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (result) if (result)
goto set_alt0; goto set_alt0;
/*
* 1 tag is reserved for untagged commands +
* 1 tag to avoid off by one errors in some bridge firmwares
*/
shost->can_queue = devinfo->qdepth - 2;
usb_set_intfdata(intf, shost); usb_set_intfdata(intf, shost);
result = scsi_add_host(shost, &intf->dev); result = scsi_add_host(shost, &intf->dev);
if (result) if (result)
......
...@@ -64,6 +64,13 @@ UNUSUAL_DEV(0x0bc2, 0x3312, 0x0000, 0x9999, ...@@ -64,6 +64,13 @@ UNUSUAL_DEV(0x0bc2, 0x3312, 0x0000, 0x9999,
USB_SC_DEVICE, USB_PR_DEVICE, NULL, USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_NO_ATA_1X), US_FL_NO_ATA_1X),
/* Reported-by: David Webb <djw@noc.ac.uk> */
UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999,
"Seagate",
"Expansion Desk",
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_NO_REPORT_LUNS),
/* Reported-by: Hans de Goede <hdegoede@redhat.com> */ /* Reported-by: Hans de Goede <hdegoede@redhat.com> */
UNUSUAL_DEV(0x0bc2, 0x3320, 0x0000, 0x9999, UNUSUAL_DEV(0x0bc2, 0x3320, 0x0000, 0x9999,
"Seagate", "Seagate",
......
...@@ -482,7 +482,7 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags) ...@@ -482,7 +482,7 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags)
US_FL_NO_READ_DISC_INFO | US_FL_NO_READ_CAPACITY_16 | US_FL_NO_READ_DISC_INFO | US_FL_NO_READ_CAPACITY_16 |
US_FL_INITIAL_READ10 | US_FL_WRITE_CACHE | US_FL_INITIAL_READ10 | US_FL_WRITE_CACHE |
US_FL_NO_ATA_1X | US_FL_NO_REPORT_OPCODES | US_FL_NO_ATA_1X | US_FL_NO_REPORT_OPCODES |
US_FL_MAX_SECTORS_240); US_FL_MAX_SECTORS_240 | US_FL_NO_REPORT_LUNS);
p = quirks; p = quirks;
while (*p) { while (*p) {
...@@ -532,6 +532,9 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags) ...@@ -532,6 +532,9 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags)
case 'i': case 'i':
f |= US_FL_IGNORE_DEVICE; f |= US_FL_IGNORE_DEVICE;
break; break;
case 'j':
f |= US_FL_NO_REPORT_LUNS;
break;
case 'l': case 'l':
f |= US_FL_NOT_LOCKABLE; f |= US_FL_NOT_LOCKABLE;
break; break;
......
...@@ -79,6 +79,8 @@ ...@@ -79,6 +79,8 @@
/* Cannot handle MI_REPORT_SUPPORTED_OPERATION_CODES */ \ /* Cannot handle MI_REPORT_SUPPORTED_OPERATION_CODES */ \
US_FLAG(MAX_SECTORS_240, 0x08000000) \ US_FLAG(MAX_SECTORS_240, 0x08000000) \
/* Sets max_sectors to 240 */ \ /* Sets max_sectors to 240 */ \
US_FLAG(NO_REPORT_LUNS, 0x10000000) \
/* Cannot handle REPORT_LUNS */ \
#define US_FLAG(name, value) US_FL_##name = value , #define US_FLAG(name, value) US_FL_##name = value ,
enum { US_DO_ALL_FLAGS }; enum { US_DO_ALL_FLAGS };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment