aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/controller/dwc3.c292
-rw-r--r--sys/dev/usb/controller/dwc3.h4
-rw-r--r--sys/dev/usb/controller/xhci.c1
-rw-r--r--sys/dev/usb/input/atp.c3
-rw-r--r--sys/dev/usb/serial/uftdi.c1
-rw-r--r--sys/dev/usb/usbdevs3
6 files changed, 238 insertions, 66 deletions
diff --git a/sys/dev/usb/controller/dwc3.c b/sys/dev/usb/controller/dwc3.c
index a3c84b40101a..19237ef4c11d 100644
--- a/sys/dev/usb/controller/dwc3.c
+++ b/sys/dev/usb/controller/dwc3.c
@@ -2,6 +2,7 @@
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2019 Emmanuel Vadot <manu@FreeBSD.Org>
+ * Copyright (c) 2021-2022 Bjoern A. Zeeb <bz@FreeBSD.ORG>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,12 +26,14 @@
* SUCH DAMAGE.
*
* $FreeBSD$
- *
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_platform.h"
+#include "opt_acpi.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -38,15 +41,11 @@ __FBSDID("$FreeBSD$");
#include <sys/condvar.h>
#include <sys/kernel.h>
#include <sys/module.h>
+#ifdef FDT
#include <sys/gpio.h>
-#include <machine/bus.h>
-
-#include <dev/fdt/simplebus.h>
+#endif
-#include <dev/fdt/fdt_common.h>
-#include <dev/ofw/ofw_bus.h>
-#include <dev/ofw/ofw_bus_subr.h>
-#include <dev/ofw/ofw_subr.h>
+#include <machine/bus.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
@@ -60,15 +59,25 @@ __FBSDID("$FreeBSD$");
#include <dev/usb/controller/xhci.h>
#include <dev/usb/controller/dwc3.h>
+#ifdef FDT
+#include <dev/fdt/simplebus.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/ofw_subr.h>
+
#include <dev/extres/clk/clk.h>
#include <dev/extres/phy/phy_usb.h>
+#endif
-#include "generic_xhci.h"
+#ifdef DEV_ACPI
+#include <contrib/dev/acpica/include/acpi.h>
+#include <contrib/dev/acpica/include/accommon.h>
+#include <dev/acpica/acpivar.h>
+#endif
-static struct ofw_compat_data compat_data[] = {
- { "snps,dwc3", 1 },
- { NULL, 0 }
-};
+#include "generic_xhci.h"
struct snps_dwc3_softc {
struct xhci_softc sc;
@@ -76,9 +85,7 @@ struct snps_dwc3_softc {
struct resource * mem_res;
bus_space_tag_t bst;
bus_space_handle_t bsh;
- phandle_t node;
- phy_t usb2_phy;
- phy_t usb3_phy;
+ uint32_t snpsid;
};
#define DWC3_WRITE(_sc, _off, _val) \
@@ -86,6 +93,8 @@ struct snps_dwc3_softc {
#define DWC3_READ(_sc, _off) \
bus_space_read_4(_sc->bst, _sc->bsh, _off)
+#define IS_DMA_32B 1
+
static int
snps_dwc3_attach_xhci(device_t dev)
{
@@ -124,7 +133,7 @@ snps_dwc3_attach_xhci(device_t dev)
return (err);
}
- err = xhci_init(sc, dev, 1);
+ err = xhci_init(sc, dev, IS_DMA_32B);
if (err != 0) {
device_printf(dev, "Failed to init XHCI, with error %d\n", err);
return (ENXIO);
@@ -146,34 +155,60 @@ snps_dwc3_attach_xhci(device_t dev)
return (0);
}
-#if 0
+#ifdef DWC3_DEBUG
static void
-snsp_dwc3_dump_regs(struct snps_dwc3_softc *sc)
+snsp_dwc3_dump_regs(struct snps_dwc3_softc *sc, const char *msg)
{
+ struct xhci_softc *xsc;
uint32_t reg;
+ if (!bootverbose)
+ return;
+
+ device_printf(sc->dev, "%s: %s:\n", __func__, msg ? msg : "");
+
reg = DWC3_READ(sc, DWC3_GCTL);
- device_printf(sc->dev, "GCTL: %x\n", reg);
+ device_printf(sc->dev, "GCTL: %#012x\n", reg);
+ reg = DWC3_READ(sc, DWC3_GUCTL);
+ device_printf(sc->dev, "GUCTL: %#012x\n", reg);
reg = DWC3_READ(sc, DWC3_GUCTL1);
- device_printf(sc->dev, "GUCTL1: %x\n", reg);
+ device_printf(sc->dev, "GUCTL1: %#012x\n", reg);
reg = DWC3_READ(sc, DWC3_GUSB2PHYCFG0);
- device_printf(sc->dev, "GUSB2PHYCFG0: %x\n", reg);
+ device_printf(sc->dev, "GUSB2PHYCFG0: %#012x\n", reg);
reg = DWC3_READ(sc, DWC3_GUSB3PIPECTL0);
- device_printf(sc->dev, "GUSB3PIPECTL0: %x\n", reg);
+ device_printf(sc->dev, "GUSB3PIPECTL0: %#012x\n", reg);
reg = DWC3_READ(sc, DWC3_DCFG);
- device_printf(sc->dev, "DCFG: %x\n", reg);
+ device_printf(sc->dev, "DCFG: %#012x\n", reg);
+
+ xsc = &sc->sc;
+ device_printf(sc->dev, "xhci quirks: %#012x\n", xsc->sc_quirks);
+}
+
+static void
+snps_dwc3_dump_ctrlparams(struct snps_dwc3_softc *sc)
+{
+ const bus_size_t offs[] = {
+ DWC3_GHWPARAMS0, DWC3_GHWPARAMS1, DWC3_GHWPARAMS2, DWC3_GHWPARAMS3,
+ DWC3_GHWPARAMS4, DWC3_GHWPARAMS5, DWC3_GHWPARAMS6, DWC3_GHWPARAMS7,
+ DWC3_GHWPARAMS8,
+ };
+ uint32_t reg;
+ int i;
+
+ for (i = 0; i < nitems(offs); i++) {
+ reg = DWC3_READ(sc, offs[i]);
+ if (bootverbose)
+ device_printf(sc->dev, "hwparams[%d]: %#012x\n", i, reg);
+ }
}
#endif
static void
snps_dwc3_reset(struct snps_dwc3_softc *sc)
{
- uint32_t gctl, phy2, phy3;
+ uint32_t gctl, ghwp0, phy2, phy3;
- if (sc->usb2_phy)
- phy_enable(sc->usb2_phy);
- if (sc->usb3_phy)
- phy_enable(sc->usb3_phy);
+ ghwp0 = DWC3_READ(sc, DWC3_GHWPARAMS0);
gctl = DWC3_READ(sc, DWC3_GCTL);
gctl |= DWC3_GCTL_CORESOFTRESET;
@@ -181,10 +216,16 @@ snps_dwc3_reset(struct snps_dwc3_softc *sc)
phy2 = DWC3_READ(sc, DWC3_GUSB2PHYCFG0);
phy2 |= DWC3_GUSB2PHYCFG0_PHYSOFTRST;
+ if ((ghwp0 & DWC3_GHWPARAMS0_MODE_MASK) ==
+ DWC3_GHWPARAMS0_MODE_DUALROLEDEVICE)
+ phy2 &= ~DWC3_GUSB2PHYCFG0_SUSPENDUSB20;
DWC3_WRITE(sc, DWC3_GUSB2PHYCFG0, phy2);
phy3 = DWC3_READ(sc, DWC3_GUSB3PIPECTL0);
phy3 |= DWC3_GUSB3PIPECTL0_PHYSOFTRST;
+ if ((ghwp0 & DWC3_GHWPARAMS0_MODE_MASK) ==
+ DWC3_GHWPARAMS0_MODE_DUALROLEDEVICE)
+ phy3 &= ~DWC3_GUSB3PIPECTL0_SUSPENDUSB3;
DWC3_WRITE(sc, DWC3_GUSB3PIPECTL0, phy3);
DELAY(1000);
@@ -209,17 +250,27 @@ snps_dwc3_configure_host(struct snps_dwc3_softc *sc)
reg &= ~DWC3_GCTL_PRTCAPDIR_MASK;
reg |= DWC3_GCTL_PRTCAPDIR_HOST;
DWC3_WRITE(sc, DWC3_GCTL, reg);
+
+ /*
+ * Enable the Host IN Auto Retry feature, making the
+ * host respond with a non-terminating retry ACK.
+ * XXX If we ever support more than host mode this needs a dr_mode check.
+ */
+ reg = DWC3_READ(sc, DWC3_GUCTL);
+ reg |= DWC3_GUCTL_HOST_AUTO_RETRY;
+ DWC3_WRITE(sc, DWC3_GUCTL, reg);
}
+#ifdef FDT
static void
-snps_dwc3_configure_phy(struct snps_dwc3_softc *sc)
+snps_dwc3_configure_phy(struct snps_dwc3_softc *sc, phandle_t node)
{
char *phy_type;
uint32_t reg;
int nphy_types;
phy_type = NULL;
- nphy_types = OF_getprop_alloc(sc->node, "phy_type", (void **)&phy_type);
+ nphy_types = OF_getprop_alloc(node, "phy_type", (void **)&phy_type);
if (nphy_types <= 0)
return;
@@ -236,12 +287,15 @@ snps_dwc3_configure_phy(struct snps_dwc3_softc *sc)
DWC3_WRITE(sc, DWC3_GUSB2PHYCFG0, reg);
OF_prop_free(phy_type);
}
+#endif
static void
snps_dwc3_do_quirks(struct snps_dwc3_softc *sc)
{
- uint32_t reg;
+ struct xhci_softc *xsc;
+ uint32_t ghwp0, reg;
+ ghwp0 = DWC3_READ(sc, DWC3_GHWPARAMS0);
reg = DWC3_READ(sc, DWC3_GUSB2PHYCFG0);
if (device_has_property(sc->dev, "snps,dis-u2-freeclk-exists-quirk"))
reg &= ~DWC3_GUSB2PHYCFG0_U2_FREECLK_EXISTS;
@@ -249,7 +303,8 @@ snps_dwc3_do_quirks(struct snps_dwc3_softc *sc)
reg |= DWC3_GUSB2PHYCFG0_U2_FREECLK_EXISTS;
if (device_has_property(sc->dev, "snps,dis_u2_susphy_quirk"))
reg &= ~DWC3_GUSB2PHYCFG0_SUSPENDUSB20;
- else
+ else if ((ghwp0 & DWC3_GHWPARAMS0_MODE_MASK) ==
+ DWC3_GHWPARAMS0_MODE_DUALROLEDEVICE)
reg |= DWC3_GUSB2PHYCFG0_SUSPENDUSB20;
if (device_has_property(sc->dev, "snps,dis_enblslpm_quirk"))
reg &= ~DWC3_GUSB2PHYCFG0_ENBLSLPM;
@@ -264,24 +319,29 @@ snps_dwc3_do_quirks(struct snps_dwc3_softc *sc)
reg = DWC3_READ(sc, DWC3_GUSB3PIPECTL0);
if (device_has_property(sc->dev, "snps,dis-del-phy-power-chg-quirk"))
- reg |= DWC3_GUSB3PIPECTL0_DELAYP1TRANS;
+ reg &= ~DWC3_GUSB3PIPECTL0_DELAYP1TRANS;
if (device_has_property(sc->dev, "snps,dis_rxdet_inp3_quirk"))
reg |= DWC3_GUSB3PIPECTL0_DISRXDETINP3;
+ if (device_has_property(sc->dev, "snps,dis_u3_susphy_quirk"))
+ reg &= ~DWC3_GUSB3PIPECTL0_SUSPENDUSB3;
+ else if ((ghwp0 & DWC3_GHWPARAMS0_MODE_MASK) ==
+ DWC3_GHWPARAMS0_MODE_DUALROLEDEVICE)
+ reg |= DWC3_GUSB3PIPECTL0_SUSPENDUSB3;
DWC3_WRITE(sc, DWC3_GUSB3PIPECTL0, reg);
+
+ /* Port Disable does not work on <= 3.00a. Disable PORT_PED. */
+ if ((sc->snpsid & 0xffff) <= 0x300a) {
+ xsc = &sc->sc;
+ xsc->sc_quirks |= XHCI_QUIRK_DISABLE_PORT_PED;
+ }
}
static int
-snps_dwc3_probe(device_t dev)
+snps_dwc3_probe_common(device_t dev)
{
- char dr_mode[16];
+ char dr_mode[16] = { 0 };
ssize_t s;
- if (!ofw_bus_status_okay(dev))
- return (ENXIO);
-
- if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
- return (ENXIO);
-
s = device_get_property(dev, "dr_mode", dr_mode, sizeof(dr_mode),
DEVICE_PROP_BUFFER);
if (s == -1) {
@@ -300,14 +360,19 @@ snps_dwc3_probe(device_t dev)
}
static int
-snps_dwc3_attach(device_t dev)
+snps_dwc3_common_attach(device_t dev, bool is_fdt)
{
struct snps_dwc3_softc *sc;
- int rid = 0;
+#ifdef FDT
+ phandle_t node;
+ phy_t usb2_phy, usb3_phy;
+#endif
+ int error, rid;
sc = device_get_softc(dev);
sc->dev = dev;
+ rid = 0;
sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
RF_ACTIVE);
if (sc->mem_res == NULL) {
@@ -317,39 +382,142 @@ snps_dwc3_attach(device_t dev)
sc->bst = rman_get_bustag(sc->mem_res);
sc->bsh = rman_get_bushandle(sc->mem_res);
+ sc->snpsid = DWC3_READ(sc, DWC3_GSNPSID);
if (bootverbose)
- device_printf(dev, "snps id: %x\n", DWC3_READ(sc, DWC3_GSNPSID));
+ device_printf(sc->dev, "snps id: %#012x\n", sc->snpsid);
+#ifdef DWC3_DEBUG
+ snps_dwc3_dump_ctrlparams(sc);
+#endif
+
+#ifdef FDT
+ if (!is_fdt)
+ goto skip_phys;
/* Get the phys */
- sc->node = ofw_bus_get_node(dev);
- phy_get_by_ofw_name(dev, sc->node, "usb2-phy", &sc->usb2_phy);
- phy_get_by_ofw_name(dev, sc->node, "usb3-phy", &sc->usb3_phy);
+ node = ofw_bus_get_node(dev);
+
+ usb2_phy = usb3_phy = NULL;
+ error = phy_get_by_ofw_name(dev, node, "usb2-phy", &usb2_phy);
+ if (error == 0 && usb2_phy != NULL)
+ phy_enable(usb2_phy);
+ error = phy_get_by_ofw_name(dev, node, "usb3-phy", &usb3_phy);
+ if (error == 0 && usb3_phy != NULL)
+ phy_enable(usb3_phy);
+
+ snps_dwc3_configure_phy(sc, node);
+skip_phys:
+#endif
snps_dwc3_reset(sc);
snps_dwc3_configure_host(sc);
- snps_dwc3_configure_phy(sc);
snps_dwc3_do_quirks(sc);
-#if 0
- snsp_dwc3_dump_regs(sc);
+
+#ifdef DWC3_DEBUG
+ snsp_dwc3_dump_regs(sc, "Pre XHCI init");
+#endif
+ error = snps_dwc3_attach_xhci(dev);
+#ifdef DWC3_DEBUG
+ snsp_dwc3_dump_regs(sc, "Post XHCI init");
#endif
- snps_dwc3_attach_xhci(dev);
- return (0);
+ return (error);
}
-static device_method_t snps_dwc3_methods[] = {
+#ifdef FDT
+static struct ofw_compat_data compat_data[] = {
+ { "snps,dwc3", 1 },
+ { NULL, 0 }
+};
+
+static int
+snps_dwc3_fdt_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return (ENXIO);
+
+ return (snps_dwc3_probe_common(dev));
+}
+
+static int
+snps_dwc3_fdt_attach(device_t dev)
+{
+
+ return (snps_dwc3_common_attach(dev, true));
+}
+
+static device_method_t snps_dwc3_fdt_methods[] = {
/* Device interface */
- DEVMETHOD(device_probe, snps_dwc3_probe),
- DEVMETHOD(device_attach, snps_dwc3_attach),
+ DEVMETHOD(device_probe, snps_dwc3_fdt_probe),
+ DEVMETHOD(device_attach, snps_dwc3_fdt_attach),
DEVMETHOD_END
};
-static driver_t snps_dwc3_driver = {
- "xhci",
- snps_dwc3_methods,
- sizeof(struct snps_dwc3_softc)
+DEFINE_CLASS_1(snps_dwc3_fdt, snps_dwc3_fdt_driver, snps_dwc3_fdt_methods,
+ sizeof(struct snps_dwc3_softc), generic_xhci_driver);
+
+DRIVER_MODULE(snps_dwc3_fdt, simplebus, snps_dwc3_fdt_driver, 0, 0);
+MODULE_DEPEND(snps_dwc3_fdt, xhci, 1, 1, 1);
+#endif
+
+#ifdef DEV_ACPI
+static char *dwc3_acpi_ids[] = {
+ "808622B7", /* This was an Intel PCI Vendor/Device ID used. */
+ "PNP0D10", /* The generic XHCI PNP ID needing extra probe checks. */
+ NULL
+};
+
+static int
+snps_dwc3_acpi_probe(device_t dev)
+{
+ char *match;
+ int error;
+
+ if (acpi_disabled("snps_dwc3"))
+ return (ENXIO);
+
+ error = ACPI_ID_PROBE(device_get_parent(dev), dev, dwc3_acpi_ids, &match);
+ if (error > 0)
+ return (ENXIO);
+
+ /*
+ * If we found the Generic XHCI PNP ID we can only attach if we have
+ * some other means to identify the device as dwc3.
+ */
+ if (strcmp(match, "PNP0D10") == 0) {
+ /* This is needed in SolidRun's HoneyComb. */
+ if (device_has_property(dev, "snps,dis_rxdet_inp3_quirk"))
+ goto is_dwc3;
+
+ return (ENXIO);
+ }
+
+is_dwc3:
+ return (snps_dwc3_probe_common(dev));
+}
+
+static int
+snps_dwc3_acpi_attach(device_t dev)
+{
+
+ return (snps_dwc3_common_attach(dev, false));
+}
+
+static device_method_t snps_dwc3_acpi_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, snps_dwc3_acpi_probe),
+ DEVMETHOD(device_attach, snps_dwc3_acpi_attach),
+
+ DEVMETHOD_END
};
-DRIVER_MODULE(snps_dwc3, simplebus, snps_dwc3_driver, 0, 0);
-MODULE_DEPEND(snps_dwc3, xhci, 1, 1, 1);
+DEFINE_CLASS_1(snps_dwc3_acpi, snps_dwc3_acpi_driver, snps_dwc3_acpi_methods,
+ sizeof(struct snps_dwc3_softc), generic_xhci_driver);
+
+DRIVER_MODULE(snps_dwc3_acpi, acpi, snps_dwc3_acpi_driver, 0, 0);
+MODULE_DEPEND(snps_dwc3_acpi, usb, 1, 1, 1);
+#endif
diff --git a/sys/dev/usb/controller/dwc3.h b/sys/dev/usb/controller/dwc3.h
index a8b127cda9a8..83951d327c8c 100644
--- a/sys/dev/usb/controller/dwc3.h
+++ b/sys/dev/usb/controller/dwc3.h
@@ -54,10 +54,13 @@
#define DWC3_GGPIO 0xc124
#define DWC3_GUID 0xc128
#define DWC3_GUCTL 0xc12C
+#define DWC3_GUCTL_HOST_AUTO_RETRY (1 << 14)
#define DWC3_GBUSERRADDRLO 0xc130
#define DWC3_GBUSERRADDRHI 0xc134
#define DWC3_GPRTBIMAPLO 0xc138
#define DWC3_GHWPARAMS0 0xc140
+#define DWC3_GHWPARAMS0_MODE_DUALROLEDEVICE 0x2
+#define DWC3_GHWPARAMS0_MODE_MASK 0x3
#define DWC3_GHWPARAMS1 0xc144
#define DWC3_GHWPARAMS2 0xc148
#define DWC3_GHWPARAMS3 0xc14C
@@ -92,6 +95,7 @@
#define DWC3_GUSB3PIPECTL0_PHYSOFTRST (1 << 31)
#define DWC3_GUSB3PIPECTL0_DISRXDETINP3 (1 << 28)
#define DWC3_GUSB3PIPECTL0_DELAYP1TRANS (1 << 18)
+#define DWC3_GUSB3PIPECTL0_SUSPENDUSB3 (1 << 17)
#define DWC3_GTXFIFOSIZ(x) (0xc300 + 0x4 * (x))
#define DWC3_GRXFIFOSIZ(x) (0xc380 + 0x4 * (x))
diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c
index 039750cb0874..045be9a40b99 100644
--- a/sys/dev/usb/controller/xhci.c
+++ b/sys/dev/usb/controller/xhci.c
@@ -581,7 +581,6 @@ xhci_init(struct xhci_softc *sc, device_t self, uint8_t dma32)
return (ENXIO);
}
- sc->sc_noport = sc->sc_noport;
sc->sc_noslot = XHCI_HCS1_DEVSLOT_MAX(temp);
DPRINTF("Max slots: %u\n", sc->sc_noslot);
diff --git a/sys/dev/usb/input/atp.c b/sys/dev/usb/input/atp.c
index 2f5487835c5e..206075694f92 100644
--- a/sys/dev/usb/input/atp.c
+++ b/sys/dev/usb/input/atp.c
@@ -2015,7 +2015,6 @@ atp_reap_sibling_zombies(void *arg)
u_int8_t n_touches_reaped = 0;
u_int8_t n_slides_reaped = 0;
u_int8_t n_horizontal_scrolls = 0;
- u_int8_t n_vertical_scrolls = 0;
int horizontal_scroll = 0;
atp_stroke_t *strokep;
atp_stroke_t *strokep_next;
@@ -2034,8 +2033,6 @@ atp_reap_sibling_zombies(void *arg)
if (atp_is_horizontal_scroll(strokep)) {
n_horizontal_scrolls++;
horizontal_scroll += strokep->cum_movement_x;
- } else if (atp_is_vertical_scroll(strokep)) {
- n_vertical_scrolls++;
}
}
diff --git a/sys/dev/usb/serial/uftdi.c b/sys/dev/usb/serial/uftdi.c
index 8678d77f4278..00a47aa00ce3 100644
--- a/sys/dev/usb/serial/uftdi.c
+++ b/sys/dev/usb/serial/uftdi.c
@@ -909,6 +909,7 @@ static const STRUCT_USB_HOST_ID uftdi_devs[] = {
UFTDI_DEV(TESTO, USB_INTERFACE, 0),
UFTDI_DEV(TML, USB_SERIAL, 0),
UFTDI_DEV(TTI, QL355P, 0),
+ UFTDI_DEV(UBLOX, XPLR_M9, 0),
UFTDI_DEV(UNKNOWN4, NF_RIC, 0),
#undef UFTDI_DEV
};
diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs
index f69dacb5fb9b..790c642bfa70 100644
--- a/sys/dev/usb/usbdevs
+++ b/sys/dev/usb/usbdevs
@@ -4774,6 +4774,9 @@ product TWINMOS MDIV 0x1325 Memory Disk IV
/* Ubiquam products */
product UBIQUAM UALL 0x3100 CDMA 1xRTT USB Modem (U-100/105/200/300/520)
+/* u-blox products */
+product UBLOX XPLR_M9 0x0501 M9 GNSS Explorer Kit
+
/* Ultima products */
product ULTIMA 1200UBPLUS 0x4002 1200 UB Plus scanner