Page MenuHomeFreeBSD

D19749.1789633511.diff
No OneTemporary

Size
54 KB
Referenced Files
None
Subscribers
None

D19749.1789633511.diff

Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -76,6 +76,16 @@
compile-with "${AWK} -f $S/tools/usbdevs2h.awk $S/dev/usb/usbdevs -d" \
no-obj no-implicit-rule before-depend \
clean "usbdevs_data.h"
+sdiodevs.h optional mmccam \
+ dependency "$S/tools/usbdevs2h.awk $S/dev/sdio/sdiodevs" \
+ compile-with "${AWK} -f $S/tools/usbdevs2h.awk $S/dev/sdio/sdiodevs -s" \
+ no-obj no-implicit-rule before-depend \
+ clean "sdiodevs.h"
+sdiodevs_data.h optional mmccam \
+ dependency "$S/tools/usbdevs2h.awk $S/dev/sdio/sdiodevs" \
+ compile-with "${AWK} -f $S/tools/usbdevs2h.awk $S/dev/sdio/sdiodevs -S" \
+ no-obj no-implicit-rule before-depend \
+ clean "sdiodevs_data.h"
cam/cam.c optional scbus
cam/cam_compat.c optional scbus
cam/cam_iosched.c optional scbus
@@ -3028,6 +3038,9 @@
dev/sdhci/sdhci_if.m optional sdhci
dev/sdhci/sdhci_acpi.c optional sdhci acpi
dev/sdhci/sdhci_pci.c optional sdhci pci
+dev/sdio/sdio_if.m optional mmccam
+dev/sdio/sdio_subr.c optional mmccam
+dev/sdio/sdiob.c optional mmccam
dev/sf/if_sf.c optional sf pci
dev/sge/if_sge.c optional sge pci
dev/siis/siis.c optional siis pci
Index: sys/conf/kmod.mk
===================================================================
--- sys/conf/kmod.mk
+++ sys/conf/kmod.mk
@@ -480,6 +480,18 @@
${AWK} -f ${SYSDIR}/tools/usbdevs2h.awk ${SYSDIR}/dev/usb/usbdevs -d
.endif
+.if !empty(SRCS:Msdiodevs.h)
+CLEANFILES+= sdiodevs.h
+sdiodevs.h: ${SYSDIR}/tools/usbdevs2h.awk ${SYSDIR}/dev/sdio/sdiodevs
+ ${AWK} -f ${SYSDIR}/tools/usbdevs2h.awk ${SYSDIR}/dev/sdio/sdiodevs -s
+.endif
+
+.if !empty(SRCS:Msdiodevs_data.h)
+CLEANFILES+= sdiodevs_data.h
+sdiodevs_data.h: ${SYSDIR}/tools/usbdevs2h.awk ${SYSDIR}/dev/sdio/sdiodevs
+ ${AWK} -f ${SYSDIR}/tools/usbdevs2h.awk ${SYSDIR}/dev/sdio/sdiodevs -S
+.endif
+
.if !empty(SRCS:Macpi_quirks.h)
CLEANFILES+= acpi_quirks.h
acpi_quirks.h: ${SYSDIR}/tools/acpi_quirks2h.awk ${SYSDIR}/dev/acpica/acpi_quirks
Index: sys/dev/sdio/sdio_if.m
===================================================================
--- /dev/null
+++ sys/dev/sdio/sdio_if.m
@@ -0,0 +1,105 @@
+#-
+# Copyright (c) 2019 The FreeBSD Foundation
+#
+# Portions of this software were developed by Björn Zeeb
+# under sponsorship from the FreeBSD Foundation.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+#include <sys/bus.h>
+#include <machine/bus.h>
+
+INTERFACE sdio;
+
+#
+# Default implementations of some methods.
+#
+CODE {
+ static int
+ null_sdio_read_direct(device_t dev __unused, uint8_t fn __unused, uint32_t addr __unused, uint8_t *val __unused)
+ {
+
+ return (ENXIO);
+ }
+
+ static int
+ null_sdio_write_direct(device_t dev __unused, uint8_t fn __unused, uint32_t addr __unused, uint8_t val __unused)
+ {
+
+ return (ENXIO);
+ }
+
+ static int
+ null_sdio_rw_extended(device_t dev __unused, uint8_t fn __unused, uint32_t addr __unused, uint32_t size __unused, uint8_t *buffer __unused, bool inaddr __unused)
+ {
+
+ return (ENXIO);
+ }
+};
+
+#
+# READ DIRECT (1byte)
+#
+METHOD int read_direct {
+ device_t dev;
+ uint8_t fn;
+ uint32_t addr;
+ uint8_t *val;
+} DEFAULT null_sdio_read_direct;
+
+#
+# WRITE DIRECT (1byte)
+#
+METHOD int write_direct {
+ device_t dev;
+ uint8_t fn;
+ uint32_t addr;
+ uint8_t val;
+} DEFAULT null_sdio_write_direct;
+
+#
+# READ EXTENDED
+#
+METHOD int read_extended {
+ device_t dev;
+ uint8_t fn;
+ uint32_t addr;
+ uint32_t size;
+ uint8_t *buffer;
+ bool incaddr;
+} DEFAULT null_sdio_rw_extended;
+
+#
+# WRITE EXTENDED
+#
+METHOD int write_extended {
+ device_t dev;
+ uint8_t fn;
+ uint32_t addr;
+ uint32_t size;
+ uint8_t *buffer;
+ bool incaddr;
+} DEFAULT null_sdio_rw_extended;
+
+# end
Index: sys/dev/sdio/sdio_subr.h
===================================================================
--- /dev/null
+++ sys/dev/sdio/sdio_subr.h
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2017 Ilya Bakulin. All rights reserved.
+ * Copyright (c) 2018-2019 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SDIO_SUBR_H_
+#define _SDIO_SUBR_H_
+
+/*
+ * This file contains structures and functions to work with SDIO cards.
+ */
+
+struct sdio_func {
+ device_t dev; /* The device to talk to CAM. */
+
+ uint8_t fn; /* Function number. */
+
+ uint8_t class; /* Class of function. */
+ uint16_t vendor; /* Manufacturer ID. */
+ uint16_t device; /* Card ID. */
+
+ uint16_t max_blksize; /* Maximum block size of function. */
+ uint16_t cur_blksize; /* Current block size of function. */
+
+ uint16_t retries; /* Retires for CAM operations. */
+ uint32_t timeout; /* Timeout. */
+};
+
+struct card_info {
+ struct sdio_func f[8];
+
+ /* Compared to R4 Number of I/O Functions we DO count F0 here. */
+ uint8_t num_funcs;
+
+ bool smb; /* Support Multiple Block Transfer */
+};
+
+#ifdef _KERNEL
+int sdio_enable_func(struct sdio_func *);
+int sdio_disable_func(struct sdio_func *);
+int sdio_set_blocksize(struct sdio_func *, uint16_t);
+
+uint8_t sdio_readb(struct sdio_func *, uint32_t, int *);
+void sdio_writeb(struct sdio_func *, uint8_t, uint32_t, int *);
+uint32_t sdio_readl(struct sdio_func *, uint32_t, int *);
+void sdio_writel(struct sdio_func *, uint32_t, uint32_t, int *);
+
+uint8_t sdio_f0_readb(struct sdio_func *, uint32_t, int *);
+void sdio_f0_writeb(struct sdio_func *, uint8_t, uint32_t, int *);
+#endif /* _KERNEL */
+
+#endif /* _SDIO_SUBR_H_ */
Index: sys/dev/sdio/sdio_subr.c
===================================================================
--- /dev/null
+++ sys/dev/sdio/sdio_subr.c
@@ -0,0 +1,188 @@
+/*-
+ * Copyright (c) 2017 Ilya Bakulin. All rights reserved.
+ * Copyright (c) 2018-2019 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <dev/sdio/sdiob.h>
+#include <dev/sdio/sdio_subr.h>
+
+#include "sdio_if.h"
+
+/* Works on F0. */
+static int
+sdio_set_bool_for_func(device_t dev, uint32_t addr, uint8_t fn, bool enable)
+{
+ int error;
+ uint8_t val;
+ bool enabled;
+
+ error = SDIO_READ_DIRECT(dev, 0, addr, &val);
+ if (error != 0)
+ return (error);
+
+ enabled = (val & (1 << fn)) ? true : false;
+ if (enabled == enable)
+ return (0);
+
+ if (enable)
+ val |= (1 << fn);
+ else
+ val &= ~(1 << fn);
+ error = SDIO_WRITE_DIRECT(dev, 0, addr, val);
+ return (error);
+}
+
+int
+sdio_enable_func(struct sdio_func *f)
+{
+
+ return (sdio_set_bool_for_func(f->dev, SD_IO_CCCR_FN_ENABLE,
+ f->fn, true));
+}
+
+int
+sdio_disable_func(struct sdio_func *f)
+{
+
+ return (sdio_set_bool_for_func(f->dev, SD_IO_CCCR_FN_ENABLE,
+ f->fn, false));
+}
+
+int
+sdio_set_blocksize(struct sdio_func *f, uint16_t bs)
+{
+ int error;
+ uint32_t addr;
+ uint16_t v;
+
+ addr = SD_IO_FBR_START * f->fn + SD_IO_FBR_IOBLKSZ;
+ v = htole16(bs);
+ error = SDIO_WRITE_EXTENDED(f->dev, f->fn, addr,
+ sizeof(v), (uint8_t *)&v, false);
+ if (error == 0)
+ f->cur_blksize = bs;
+
+ return (error);
+}
+
+uint8_t
+sdio_readb(struct sdio_func *f, uint32_t addr, int *err)
+{
+ int error;
+ uint8_t v;
+
+ error = SDIO_READ_DIRECT(f->dev, f->fn, addr, &v);
+ if (error) {
+ if (err != NULL)
+ *err = error;
+ return (0xff);
+ } else {
+ if (err != NULL)
+ *err = 0;
+ return (v);
+ }
+}
+
+void
+sdio_writeb(struct sdio_func *f, uint8_t val, uint32_t addr, int *err)
+{
+ int error;
+
+ error = SDIO_WRITE_DIRECT(f->dev, f->fn, addr, val);
+ if (err != NULL)
+ *err = error;
+}
+
+uint32_t
+sdio_readl(struct sdio_func *f, uint32_t addr, int *err)
+{
+ int error;
+ uint32_t v;
+
+ error = SDIO_READ_EXTENDED(f->dev, f->fn, addr, sizeof(v),
+ (uint8_t *)&v, false);
+ if (error) {
+ if (err != NULL)
+ *err = error;
+ return (0xffffffff);
+ } else {
+ if (err != NULL)
+ *err = 0;
+ return (le32toh(v));
+ }
+}
+
+void
+sdio_writel(struct sdio_func *f, uint32_t val, uint32_t addr, int *err)
+{
+ int error;
+
+ error = SDIO_WRITE_EXTENDED(f->dev, f->fn, addr, sizeof(val),
+ (uint8_t *)&val, false);
+ if (err != NULL)
+ *err = error;
+}
+
+uint8_t
+sdio_f0_readb(struct sdio_func *f, uint32_t addr, int *err)
+{
+ int error;
+ uint8_t v;
+
+ error = SDIO_READ_DIRECT(f->dev, 0, addr, &v);
+ if (error) {
+ if (err != NULL)
+ *err = error;
+ return (0xff);
+ } else {
+ if (err != NULL)
+ *err = 0;
+ return (v);
+ }
+}
+
+void
+sdio_f0_writeb(struct sdio_func *f, uint8_t val, uint32_t addr, int *err)
+{
+ int error;
+
+ error = SDIO_WRITE_DIRECT(f->dev, 0, addr, val);
+ if (err != NULL)
+ *err = error;
+}
+
+/* end */
Index: sys/dev/sdio/sdiob.h
===================================================================
--- /dev/null
+++ sys/dev/sdio/sdiob.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2019 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SDIOB_H
+#define _SDIOB_H
+
+#define SDIOB_NAME sdiob
+#define _SDIOB_NAME_S(x) __STRING(x)
+#define SDIOB_NAME_S _SDIOB_NAME_S(SDIOB_NAME)
+
+#define SDIO_VENDOR_ANY (0x0000)
+#define SDIO_DEVICE_ANY (0x0000)
+
+uint16_t sdio_get_vendor(device_t);
+uint16_t sdio_get_device(device_t);
+struct sdio_func *sdio_get_function(device_t, uint8_t);
+
+#endif /* _SDIOB_H */
Index: sys/dev/sdio/sdiob.c
===================================================================
--- /dev/null
+++ sys/dev/sdio/sdiob.c
@@ -0,0 +1,1190 @@
+/*-
+ * Copyright (c) 2017 Ilya Bakulin. All rights reserved.
+ * Copyright (c) 2018-2019 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Implements the (kernel specific) SDIO parts.
+ * This will hide all cam(4) functionality from the SDIO driver implementations
+ * which will just be newbus/device(9) and hence look like any other driver for,
+ * e.g., PCI.
+ * The sdiob(4) parts effetively "translate" between the two worlds "bridging"
+ * messages from MMCCAM to newbus and back.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_cam.h"
+
+#include <sys/systm.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/types.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_queue.h>
+#include <cam/cam_periph.h>
+#include <cam/cam_xpt.h>
+#include <cam/cam_xpt_periph.h>
+#include <cam/cam_xpt_internal.h> /* for cam_path */
+#include <cam/cam_debug.h>
+
+#include <dev/sdio/sdiob.h>
+#include <dev/sdio/sdio_subr.h>
+
+#include "sdio_if.h"
+
+#ifdef DEBUG
+#define DPRINTF(...) printf(__VA_ARGS__)
+#define DPRINTFDEV(_dev, ...) device_printf((_dev), __VA_ARGS__)
+#else
+#define DPRINTF(...)
+#define DPRINTFDEV(_dev, ...)
+#endif
+
+struct sdiob_softc {
+ uint32_t sdio_state;
+#define SDIO_STATE_DEAD 0x0001
+#define SDIO_STATE_INITIALIZING 0x0002
+#define SDIO_STATE_READY 0x0004
+ uint32_t nb_state;
+#define NB_STATE_DEAD 0x0001
+#define NB_STATE_SIM_ADDED 0x0002
+#define NB_STATE_READY 0x0004
+
+ /* CAM side (including sim_dev). */
+ struct card_info cardinfo;
+ struct cam_periph *periph;
+ union ccb *ccb;
+ struct task discover_task;
+
+ /* Newbus side. */
+ device_t dev; /* Ourselves. */
+ device_t child;
+};
+
+
+/* -------------------------------------------------------------------------- */
+/*
+ * Helper functions for driver probe/attach to get the "vendor" and "device"
+ * information from F0 to be able to decide whether to attach or not.
+ * Also an accessor function to return the sdio_func * by number.
+ *
+ * Given these functions operate on the softc their implementation is here and
+ * not in in sdio_subr.c.
+ */
+
+uint16_t
+sdio_get_vendor(device_t dev)
+{
+ device_t pdev;
+ struct sdiob_softc *sc;
+
+ if (dev == NULL)
+ return (SDIO_VENDOR_ANY);
+
+ pdev = device_get_parent(dev);
+ if (pdev == NULL)
+ return (SDIO_VENDOR_ANY);
+
+ sc = device_get_softc(pdev);
+ if (sc == NULL)
+ return (SDIO_VENDOR_ANY);
+
+ if (sc->cardinfo.num_funcs < 1)
+ return (SDIO_VENDOR_ANY);
+
+ return (sc->cardinfo.f[0].vendor);
+}
+
+uint16_t
+sdio_get_device(device_t dev)
+{
+ device_t pdev;
+ struct sdiob_softc *sc;
+
+ if (dev == NULL)
+ return (SDIO_VENDOR_ANY);
+
+ pdev = device_get_parent(dev);
+ if (pdev == NULL)
+ return (SDIO_VENDOR_ANY);
+
+ sc = device_get_softc(pdev);
+ if (sc == NULL)
+ return (SDIO_VENDOR_ANY);
+
+ if (sc->cardinfo.num_funcs < 1)
+ return (SDIO_VENDOR_ANY);
+
+ return (sc->cardinfo.f[0].device);
+}
+
+struct sdio_func *
+sdio_get_function(device_t dev, uint8_t fn)
+{
+ struct sdiob_softc *sc;
+
+ if (dev == NULL)
+ return (NULL);
+
+ sc = device_get_softc(dev);
+ if (sc == NULL)
+ return (NULL);
+
+ if (sc->cardinfo.num_funcs < fn)
+ return (NULL);
+
+ return (&sc->cardinfo.f[fn]);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/*
+ * SDIO CMD52 and CM53 implementations along with wrapper functions for
+ * read/write and a CAM periph helper function.
+ * These are the backend implementations of the sdio_if.m framework talking
+ * through CAM to sdhci.
+ * Note: these functions are also called during early discovery stage when
+ * we are not a device(9) yet. Hence they cannot always use device_printf()
+ * to log errors and have to call CAM_DEBUG() during these early stages.
+ */
+
+static int
+sdioerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
+{
+
+ return (cam_periph_error(ccb, cam_flags, sense_flags));
+}
+
+/* CMD52: direct byte access. */
+static int
+sdio_rw_direct_sc(struct sdiob_softc *sc, uint8_t fn, uint32_t addr, bool wr,
+ uint8_t *val)
+{
+ uint32_t arg, flags;
+ int error;
+
+ KASSERT((val != NULL), ("%s val passed as NULL\n", __func__));
+
+ if (sc->ccb == NULL)
+ sc->ccb = xpt_alloc_ccb();
+ else
+ memset(sc->ccb, 0, sizeof(*sc->ccb));
+ xpt_setup_ccb(&sc->ccb->ccb_h, sc->periph->path, CAM_PRIORITY_NONE);
+ CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_TRACE,
+ ("%s(fn=%d, addr=%#02x, wr=%d, *val=%#02x)\n", __func__,
+ fn, addr, wr, *val));
+
+ flags = MMC_RSP_R5 | MMC_CMD_AC;
+ arg = SD_IO_RW_FUNC(fn) | SD_IO_RW_ADR(addr);
+ if (wr)
+ arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*val);
+
+ cam_fill_mmcio(&sc->ccb->mmcio,
+ /*retries*/ 0,
+ /*cbfcnp*/ NULL,
+ /*flags*/ CAM_DIR_NONE,
+ /*mmc_opcode*/ SD_IO_RW_DIRECT,
+ /*mmc_arg*/ arg,
+ /*mmc_flags*/ flags,
+ /*mmc_data*/ 0,
+ /*timeout*/ 5000);
+ error = cam_periph_runccb(sc->ccb, sdioerror, CAM_FLAG_NONE, 0, NULL);
+ if (error != 0) {
+ if (sc->dev != NULL)
+ device_printf(sc->dev,
+ "%s: Failed to %s address %#10x error=%d\n",
+ __func__, (wr) ? "write" : "read", addr, error);
+ else
+ CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_INFO,
+ ("%s: Failed to %s address: %#10x error=%d\n",
+ __func__, (wr) ? "write" : "read", addr, error));
+ return (error);
+ }
+
+ /* TODO: Add handling of MMC errors */
+ /* ccb->mmcio.cmd.error ? */
+ if (wr == false)
+ *val = sc->ccb->mmcio.cmd.resp[0] & 0xff;
+
+ return (0);
+}
+
+static int
+sdio_rw_direct(device_t dev, uint8_t fn, uint32_t addr, bool wr,
+ uint8_t *val)
+{
+ struct sdiob_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+ cam_periph_lock(sc->periph);
+ error = sdio_rw_direct_sc(sc, fn, addr, wr, val);
+ cam_periph_unlock(sc->periph);
+ return (error);
+}
+
+static int
+sdiob_read_direct(device_t dev, uint8_t fn, uint32_t addr, uint8_t *val)
+{
+ int error;
+ uint8_t v;
+
+ error = sdio_rw_direct(dev, fn, addr, false, &v);
+ /* Be polite and do not touch the value on read error. */
+ if (error == 0 && val != NULL)
+ *val = v;
+ return (error);
+}
+
+static int
+sdiob_write_direct(device_t dev, uint8_t fn, uint32_t addr, uint8_t val)
+{
+
+ return (sdio_rw_direct(dev, fn, addr, true, &val));
+}
+
+/*
+ * CMD53: IO_RW_EXTENDED, read and write multiple I/O registers.
+ * Increment false gets FIFO mode (single register address).
+ */
+static int
+sdio_rw_extended_sc(struct sdiob_softc *sc, uint8_t fn, uint32_t addr,
+ bool wr, uint32_t size, uint8_t *buffer, bool incaddr)
+{
+ struct mmc_data mmcd;
+ uint32_t arg, cam_flags, flags, len;
+ int error;
+ uint16_t b_count, l;
+
+ if (sc->ccb == NULL)
+ sc->ccb = xpt_alloc_ccb();
+ else
+ memset(sc->ccb, 0, sizeof(*sc->ccb));
+ xpt_setup_ccb(&sc->ccb->ccb_h, sc->periph->path, CAM_PRIORITY_NONE);
+ CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_TRACE,
+ ("%s(fn=%d, addr=%#0x, wr=%d, size=%u buf=%p incr=%d)\n",
+ __func__, fn, addr, wr, size, buffer, incaddr));
+
+ /*
+ * If block mode is supported and we have at least 4 bytes to write and
+ * the size is at least one block, then start doing blk transfers.
+ */
+ while (sc->cardinfo.smb &&
+#ifndef __notyet__
+ /* For now disable blk writes as they lead to CRC Dat errors on RPi. */
+ !wr &&
+#endif
+ size > 4 && size >= sc->cardinfo.f[fn].cur_blksize) {
+
+ b_count = size / sc->cardinfo.f[fn].cur_blksize;
+ KASSERT(b_count >= 1, ("%s: block count to small %u size %u "
+ "cur_blksize %u\n", __func__, b_count, size,
+ sc->cardinfo.f[fn].cur_blksize));
+
+#ifdef __notyet__
+ /* XXX support inifinite transfer with b_count = 0. */
+#else
+ if (b_count > 511)
+ b_count = 511;
+ /* Force to 1 blk to see if that works. */
+ b_count = 1;
+ len = b_count * sc->cardinfo.f[fn].cur_blksize;
+#endif
+ flags = MMC_RSP_R5 | MMC_CMD_ADTC;
+ arg = SD_IOE_RW_FUNC(fn) | SD_IOE_RW_BLK |
+ SD_IOE_RW_ADR(addr) | SD_IOE_RW_LEN(b_count);
+ if (incaddr)
+ arg |= SD_IOE_RW_INCR;
+
+ memset(&mmcd, 0, sizeof(mmcd));
+ mmcd.data = buffer;
+ mmcd.len = len;
+ /* That's just silly as those are both known from elsewhere, aren't they? */
+ mmcd.block_size = sc->cardinfo.f[fn].cur_blksize;
+ mmcd.block_count = b_count;
+
+ if (wr) {
+ arg |= SD_IOE_RW_WR;
+ cam_flags = CAM_DIR_OUT;
+ mmcd.flags = MMC_DATA_WRITE;
+ } else {
+ cam_flags = CAM_DIR_IN;
+ mmcd.flags = MMC_DATA_READ;
+ }
+#ifdef __notyet__
+ if (b_count == 0)
+ /* XXX. Cancel I/O: CCCR -> ASx */
+ /* Stop cmd. */
+#endif
+ cam_fill_mmcio(&sc->ccb->mmcio,
+ /*retries*/ 0,
+ /*cbfcnp*/ NULL,
+ /*flags*/ cam_flags,
+ /*mmc_opcode*/ SD_IO_RW_EXTENDED,
+ /*mmc_arg*/ arg,
+ /*mmc_flags*/ flags,
+ /*mmc_data*/ &mmcd,
+ /*timeout*/ b_count * 5000); /* XXX retries/timeout from func. */
+
+ if (b_count > 1) {
+ sc->ccb->mmcio.cmd.data->flags |= MMC_DATA_MULTI;
+#if 0
+ /* Stop command? */
+#endif
+ }
+ error = cam_periph_runccb(sc->ccb, sdioerror, CAM_FLAG_NONE, 0, NULL);
+ if (error != 0) {
+ if (sc->dev != NULL)
+ device_printf(sc->dev,
+ "%s: Failed to %s address %#10x buffer %p size %u "
+ "%s b_count %u error=%d\n",
+ __func__, (wr) ? "write to" : "read from", addr,
+ buffer, len, (incaddr) ? "incr" : "fixed",
+ b_count, error);
+ else
+ CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_INFO,
+ ("%s: Failed to %s address %#10x buffer %p size %u "
+ "%s b_count %u error=%d\n",
+ __func__, (wr) ? "write to" : "read from", addr,
+ buffer, len, (incaddr) ? "incr" : "fixed",
+ b_count, error));
+ return (error);
+ }
+
+ /* TODO: Add handling of MMC errors */
+ /* ccb->mmcio.cmd.error ? */
+ error = sc->ccb->mmcio.cmd.resp[0] & 0xff;
+ if (error != 0) {
+ if (sc->dev != NULL)
+ device_printf(sc->dev,
+ "%s: Failed to %s address %#10x buffer %p size %u "
+ "%s b_count %u mmcio resp error=%d\n",
+ __func__, (wr) ? "write to" : "read from", addr,
+ buffer, len, (incaddr) ? "incr" : "fixed",
+ b_count, error);
+ else
+ CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_INFO,
+ ("%s: Failed to %s address %#10x buffer %p size %u "
+ "%s b_count %u mmcio resp error=%d\n",
+ __func__, (wr) ? "write to" : "read from", addr,
+ buffer, len, (incaddr) ? "incr" : "fixed",
+ b_count, error));
+ return (error);
+ }
+
+ size -= len;
+ buffer += len;
+ if (incaddr)
+ addr += len;
+ }
+
+ len = size;
+ while (len > 0) {
+ l = MIN(len, sc->cardinfo.f[fn].cur_blksize);
+
+ flags = MMC_RSP_R5 | MMC_CMD_ADTC;
+ arg = SD_IOE_RW_FUNC(fn) | SD_IOE_RW_ADR(addr) | SD_IOE_RW_LEN(l);
+ if (incaddr)
+ arg |= SD_IOE_RW_INCR;
+
+ memset(&mmcd, 0, sizeof(mmcd));
+ mmcd.data = buffer;
+ mmcd.len = l;
+
+ if (wr) {
+ arg |= SD_IO_RW_WR;
+ cam_flags = CAM_DIR_OUT;
+ mmcd.flags = MMC_DATA_WRITE;
+ } else {
+ cam_flags = CAM_DIR_IN;
+ mmcd.flags = MMC_DATA_READ;
+ }
+ cam_fill_mmcio(&sc->ccb->mmcio,
+ /*retries*/ 0,
+ /*cbfcnp*/ NULL,
+ /*flags*/ cam_flags,
+ /*mmc_opcode*/ SD_IO_RW_EXTENDED,
+ /*mmc_arg*/ arg,
+ /*mmc_flags*/ flags,
+ /*mmc_data*/ &mmcd,
+ /*timeout*/ 5000); /* XXX retries/timeout from func. */
+ error = cam_periph_runccb(sc->ccb, sdioerror, CAM_FLAG_NONE, 0, NULL);
+ if (error != 0) {
+ if (sc->dev != NULL)
+ device_printf(sc->dev,
+ "%s: Failed to %s address %#10x buffer %p size %u "
+ "%s error=%d\n",
+ __func__, (wr) ? "write to" : "read from", addr,
+ buffer, l, (incaddr) ? "incr" : "fixed",
+ error);
+ else
+ CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_INFO,
+ ("%s: Failed to %s address %#10x buffer %p size %u "
+ "%s error=%d\n",
+ __func__, (wr) ? "write to" : "read from", addr,
+ buffer, l, (incaddr) ? "incr" : "fixed",
+ error));
+ return (error);
+ }
+
+ /* TODO: Add handling of MMC errors */
+ /* ccb->mmcio.cmd.error ? */
+ error = sc->ccb->mmcio.cmd.resp[0] & 0xff;
+ if (error != 0) {
+ if (sc->dev != NULL)
+ device_printf(sc->dev,
+ "%s: Failed to %s address %#10x buffer %p size %u "
+ "%s mmcio resp error=%d\n",
+ __func__, (wr) ? "write to" : "read from", addr,
+ buffer, l, (incaddr) ? "incr" : "fixed",
+ error);
+ else
+ CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_INFO,
+ ("%s: Failed to %s address %#10x buffer %p size %u "
+ "%s mmcio resp error=%d\n",
+ __func__, (wr) ? "write to" : "read from", addr,
+ buffer, l, (incaddr) ? "incr" : "fixed",
+ error));
+ return (error);
+ }
+
+ /* Prepare for next iteration. */
+ len -= l;
+ buffer += l;
+ if (incaddr)
+ addr += l;
+ }
+
+ return (error);
+}
+
+static int
+sdio_rw_extended(device_t dev, uint8_t fn, uint32_t addr, bool wr,
+ uint32_t size, uint8_t *buffer, bool incaddr)
+{
+ struct sdiob_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+ cam_periph_lock(sc->periph);
+ error = sdio_rw_extended_sc(sc, fn, addr, wr, size, buffer, incaddr);
+ cam_periph_unlock(sc->periph);
+ return (error);
+}
+
+static int
+sdiob_read_extended(device_t dev, uint8_t fn, uint32_t addr, uint32_t size,
+ uint8_t *buffer, bool incaddr)
+{
+
+ return (sdio_rw_extended(dev, fn, addr, false, size, buffer, incaddr));
+}
+
+static int
+sdiob_write_extended(device_t dev, uint8_t fn, uint32_t addr, uint32_t size,
+ uint8_t *buffer, bool incaddr)
+{
+
+ return (sdio_rw_extended(dev, fn, addr, true, size, buffer, incaddr));
+}
+
+
+/* -------------------------------------------------------------------------- */
+/*
+ * Newbus functions for ourselves to probe/attach/detach and become a proper
+ * device(9). Attach will also probe for child devices (another driver
+ * implementing SDIO).
+ */
+
+static int
+sdiob_probe(device_t dev)
+{
+
+ device_set_desc(dev, "SDIO CAM-Newbus bridge");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+sdiob_attach(device_t dev)
+{
+ struct sdiob_softc *sc;
+ int error, i;
+
+ sc = device_get_softc(dev);
+ if (sc == NULL)
+ return (ENXIO);
+
+ /*
+ * Now that we are a dev, initialize the backpointer in the
+ * sdio function structures so we can pass them around and
+ * directly call CAM operations.
+ * Do this before any child gets a chance to attach.
+ */
+ for (i = 0; i < sc->cardinfo.num_funcs; i++)
+ sc->cardinfo.f[i].dev = dev;
+
+ /*
+ * XXX-BZ we might want to add one child per valid function later?
+ * While other implementations seem to do this it only makes sense if
+ * we discover split-personality cards as otherwise device drivers
+ * will see n probe/attach cycles and have to independently claim
+ * functions and then glue them back together to one device, like:
+ * / -- F0 -- \
+ * sdiob - -- F1 -- - foo_dev(9)
+ * \ -- F2 -- /
+ * \ -- F3
+ * This seems to complex for now. If we will be forced to do this
+ * at a later time, we shall not probe/attach for F0 but make it
+ * available through F<n> using special accessor function as we
+ * already starting to have, e.g., sdio_f0_readb().
+ * For now it is all-or-nothing.
+ */
+ sc->child = device_add_child(dev, NULL, -1);
+ if (sc->child == NULL) {
+ device_printf(dev, "%s: failed to add child\n", __func__);
+ return (ENXIO);
+ }
+ error = device_probe_and_attach(sc->child);
+ if (error != 0) {
+ DPRINTFDEV(dev, "%s: device_probe_and_attach(%p %s) "
+ "failed %d, no child yet.\n", __func__, sc->child,
+ device_get_nameunit(sc->child), error);
+ /*
+ * Do not delete the child or a driver loading later
+ * will have nothing to attach to!
+ */
+#if 0
+ if (device_delete_child(dev, sc->child) == 0)
+ sc->child = NULL;
+ return (ENXIO);
+#endif
+ }
+
+ sc->nb_state = NB_STATE_READY;
+
+ cam_periph_lock(sc->periph);
+ xpt_announce_periph(sc->periph, NULL);
+ cam_periph_unlock(sc->periph);
+
+ return (0);
+}
+
+static int
+sdiob_detach(device_t dev)
+{
+
+ /* XXX TODO? */
+ return (EOPNOTSUPP);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/*
+ * driver(9) and device(9) "control plane".
+ * This is what we use when we are making ourselves a device(9) in order to
+ * provide a newbus interface again, as well as the implementation of the
+ * SDIO interface.
+ */
+
+static device_method_t sdiob_methods[] = {
+
+ /* Device interface. */
+ DEVMETHOD(device_probe, sdiob_probe),
+ DEVMETHOD(device_attach, sdiob_attach),
+ DEVMETHOD(device_detach, sdiob_detach),
+
+ /* Bus interface. */
+ DEVMETHOD(bus_add_child, bus_generic_add_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* SDIO interface. */
+ DEVMETHOD(sdio_read_direct, sdiob_read_direct),
+ DEVMETHOD(sdio_write_direct, sdiob_write_direct),
+ DEVMETHOD(sdio_read_extended, sdiob_read_extended),
+ DEVMETHOD(sdio_write_extended, sdiob_write_extended),
+
+ DEVMETHOD_END
+};
+
+static devclass_t sdiob_devclass;
+static driver_t sdiob_driver = {
+ SDIOB_NAME_S,
+ sdiob_methods,
+ 0
+};
+
+
+/* -------------------------------------------------------------------------- */
+/*
+ * CIS related.
+ * Read card and function information and populate the cardinfo structure.
+ */
+
+static int
+sdio_read_direct_sc(struct sdiob_softc *sc, uint8_t fn, uint32_t addr,
+ uint8_t *val)
+{
+ int error;
+ uint8_t v;
+
+ error = sdio_rw_direct_sc(sc, fn, addr, false, &v);
+ if (error == 0 && val != NULL)
+ *val = v;
+ return (error);
+}
+
+static int
+sdio_func_read_cis(struct sdiob_softc *sc, uint8_t fn, uint32_t cis_addr)
+{
+ char cis1_info_buf[256];
+ char *cis1_info[4];
+ int start, i, count, ret;
+ uint32_t addr;
+ uint8_t ch, tuple_id, tuple_len, tuple_count, v;
+
+ /* If we encounter any read errors, abort and return. */
+#define ERR_OUT(ret) \
+ if (ret != 0) \
+ goto err;
+ ret = 0;
+ /* Use to prevent infinite loop in case of parse errors. */
+ tuple_count = 0;
+ memset(cis1_info_buf, 0, 256);
+ do {
+ addr = cis_addr;
+ ret = sdio_read_direct_sc(sc, 0, addr++, &tuple_id);
+ ERR_OUT(ret);
+ if (tuple_id == SD_IO_CISTPL_END)
+ break;
+ if (tuple_id == 0) {
+ cis_addr++;
+ continue;
+ }
+ ret = sdio_read_direct_sc(sc, 0, addr++, &tuple_len);
+ ERR_OUT(ret);
+ if (tuple_len == 0) {
+ CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_PERIPH,
+ ("%s: parse error: 0-length tuple %#02x\n",
+ __func__, tuple_id));
+ return (EIO);
+ }
+
+ switch (tuple_id) {
+ case SD_IO_CISTPL_VERS_1:
+ addr += 2;
+ for (count = 0, start = 0, i = 0;
+ (count < 4) && ((i + 4) < 256); i++) {
+ ret = sdio_read_direct_sc(sc, 0, addr + i, &ch);
+ ERR_OUT(ret);
+ DPRINTF("%s: count=%d, start=%d, i=%d, got "
+ "(%#02x)\n", __func__, count, start, i, ch);
+ if (ch == 0xff)
+ break;
+ cis1_info_buf[i] = ch;
+ if (ch == 0) {
+ cis1_info[count] =
+ cis1_info_buf + start;
+ start = i + 1;
+ count++;
+ }
+ }
+ /* XXX printfs as part of a parsing API seem odd. */
+ printf("Card info: ");
+ for (i=0; i < 4; i++)
+ if (cis1_info[i])
+ printf(" %s", cis1_info[i]);
+ printf("\n");
+ break;
+ case SD_IO_CISTPL_MANFID:
+ /* TPLMID_MANF */
+ ret = sdio_read_direct_sc(sc, 0, addr++, &v);
+ ERR_OUT(ret);
+ sc->cardinfo.f[fn].vendor = v;
+ ret = sdio_read_direct_sc(sc, 0, addr++, &v);
+ ERR_OUT(ret);
+ sc->cardinfo.f[fn].vendor |= (v << 8);
+ /* TPLMID_CARD */
+ ret = sdio_read_direct_sc(sc, 0, addr++, &v);
+ ERR_OUT(ret);
+ sc->cardinfo.f[fn].device = v;
+ ret = sdio_read_direct_sc(sc, 0, addr, &v);
+ ERR_OUT(ret);
+ sc->cardinfo.f[fn].device |= (v << 8);
+ break;
+ case SD_IO_CISTPL_FUNCID:
+ /* not sure if we need to parse it? */
+ break;
+ case SD_IO_CISTPL_FUNCE:
+ if (tuple_len < 4) {
+ printf("%s: FUNCE is too short: %d\n",
+ __func__, tuple_len);
+ break;
+ }
+ /* TPLFE_TYPE (Extended Data) */
+ ret = sdio_read_direct_sc(sc, 0, addr++, &v);
+ ERR_OUT(ret);
+ if (fn == 0) {
+ if (v != 0x00)
+ break;
+ } else {
+ if (v != 0x01)
+ break;
+ addr += 0x0b;
+ }
+ ret = sdio_read_direct_sc(sc, 0, addr, &v);
+ ERR_OUT(ret);
+ sc->cardinfo.f[fn].max_blksize = v;
+ ret = sdio_read_direct_sc(sc, 0, addr+1, &v);
+ ERR_OUT(ret);
+ sc->cardinfo.f[fn].max_blksize |= (v << 8);
+ break;
+ default:
+ CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_PERIPH,
+ ("%s: Skipping fn %d tuple %d ID %#02x "
+ "len %#02x\n", __func__, fn, tuple_count,
+ tuple_id, tuple_len));
+ }
+ if (tuple_len == 0xff) {
+ /* Also marks the end of a tuple chain (E1 16.2) */
+ /* The tuple is valid, hence this going at the end. */
+ break;
+ }
+ cis_addr += 2 + tuple_len;
+ tuple_count++;
+ } while (tuple_count < 20);
+err:
+#undef ERR_OUT
+ return (ret);
+}
+
+static uint32_t
+sdio_get_common_cis_addr(struct sdiob_softc *sc)
+{
+ uint32_t addr;
+ int error;
+ uint8_t val;
+
+ error = sdio_read_direct_sc(sc, 0, SD_IO_CCCR_CISPTR + 0, &val);
+ if (error != 0) {
+ /* XXX print error */
+ return (0xffffffff);
+ }
+ addr = val;
+ error = sdio_read_direct_sc(sc, 0, SD_IO_CCCR_CISPTR + 1, &val);
+ if (error != 0) {
+ /* XXX print error */
+ return (0xffffffff);
+ }
+ addr |= (val << 8);
+ error = sdio_read_direct_sc(sc, 0, SD_IO_CCCR_CISPTR + 2, &val);
+ if (error != 0) {
+ /* XXX print error */
+ return (0xffffffff);
+ }
+ addr |= (val << 16);
+
+ if (addr < SD_IO_CIS_START || addr > SD_IO_CIS_START + SD_IO_CIS_SIZE) {
+ CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_PERIPH,
+ ("%s: bad CIS address: %#04x\n", __func__, addr));
+ addr = 0xffffffff;
+ }
+
+ return (addr);
+}
+
+static int
+sdiob_get_card_info(struct sdiob_softc *sc)
+{
+ struct mmc_params *mmcp;
+ uint32_t cis_addr, fbr_addr;
+ int fn, error;
+ uint8_t fn_max, val;
+
+ cis_addr = sdio_get_common_cis_addr(sc);
+ if (cis_addr == 0xff)
+ return (-1);
+
+ memset(&sc->cardinfo, 0, sizeof(sc->cardinfo));
+
+ /* F0 must always be present. */
+ fn = 0;
+ error = sdio_func_read_cis(sc, fn, cis_addr);
+ if (error != 0)
+ return (error);
+ sc->cardinfo.num_funcs++;
+ /* Read CCCR Card Capability. */
+ error = sdio_read_direct_sc(sc, 0, SD_IO_CCCR_CARDCAP, &val);
+ if (error != 0) {
+ /* XXX print error */
+ return (error);
+ }
+ sc->cardinfo.smb = (val & CCCR_CC_SMB) ? true : false;
+ DPRINTF("%s: F%d: Vendor %#04x product %#04x max block size %d bytes "
+ "smb %s\n",
+ __func__, fn, sc->cardinfo.f[fn].vendor, sc->cardinfo.f[fn].device,
+ sc->cardinfo.f[fn].max_blksize, sc->cardinfo.smb ? "yes" : "no");
+
+ /* mmcp->sdio_func_count contains the number of functions w/o F0. */
+ mmcp = &sc->ccb->ccb_h.path->device->mmc_ident_data;
+ fn_max = MIN(mmcp->sdio_func_count + 1, nitems(sc->cardinfo.f));
+ for (fn = 1; fn < fn_max; fn++) {
+
+ fbr_addr = SD_IO_FBR_START * fn + SD_IO_FBR_CIS_OFFSET;
+
+ error = sdio_read_direct_sc(sc, 0, fbr_addr++, &val);
+ if (error != 0)
+ break;
+ cis_addr = val;
+ error = sdio_read_direct_sc(sc, 0, fbr_addr++, &val);
+ if (error != 0)
+ break;
+ cis_addr |= (val << 8);
+ error = sdio_read_direct_sc(sc, 0, fbr_addr++, &val);
+ if (error != 0)
+ break;
+ cis_addr |= (val << 16);
+
+ error = sdio_func_read_cis(sc, fn, cis_addr);
+ if (error != 0)
+ break;
+
+ /* Read the Standard SDIO Function Interface Code. */
+ fbr_addr = SD_IO_FBR_START * fn;
+ error = sdio_read_direct_sc(sc, 0, fbr_addr++, &val);
+ if (error != 0)
+ break;
+ sc->cardinfo.f[fn].class = (val & 0x0f);
+ if (sc->cardinfo.f[fn].class == 0x0f) {
+ error = sdio_read_direct_sc(sc, 0, fbr_addr, &val);
+ if (error != 0)
+ break;
+ sc->cardinfo.f[fn].class = val;
+ }
+
+ sc->cardinfo.f[fn].fn = fn;
+ sc->cardinfo.f[fn].cur_blksize = sc->cardinfo.f[fn].max_blksize;
+ sc->cardinfo.f[fn].retries = 0;
+ sc->cardinfo.f[fn].timeout = 5000;
+
+ DPRINTF("%s: F%d: Class %d Vendor %#04x product %#04x "
+ "max_blksize %d bytes\n", __func__, fn,
+ sc->cardinfo.f[fn].class,
+ sc->cardinfo.f[fn].vendor, sc->cardinfo.f[fn].device,
+ sc->cardinfo.f[fn].max_blksize);
+ if (sc->cardinfo.f[fn].vendor == 0) {
+ DPRINTF("%s: F%d doesn't exist\n", __func__, fn);
+ break;
+ }
+ sc->cardinfo.num_funcs++;
+ }
+ return (error);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/*
+ * CAM periph registration, allocation, and detached from that a discovery
+ * task, which goes off reads cardinfo, and then adds ourselves to our SIM's
+ * device addingt he devclass and registering the driver. This keeps the
+ * newbus chain connected though we will talk CAM in the middle (until one
+ * day CAM might be newbusyfied).
+ */
+
+static int
+sdio_newbus_sim_add(struct sdiob_softc *sc)
+{
+ device_t pdev;
+ devclass_t bus_devclass;
+ int error;
+
+ /* Add ourselves to our parent (SIM) device. */
+
+ /* Add ourselves to our parent. That way we can become a parent. */
+ KASSERT(sc->periph->sim->sim_dev != NULL, ("%s: sim_dev is NULL, sc %p "
+ "periph %p sim %p\n", __func__, sc, sc->periph, sc->periph->sim));
+
+ if (sc->dev == NULL)
+ sc->dev = BUS_ADD_CHILD(sc->periph->sim->sim_dev, 0,
+ SDIOB_NAME_S, -1);
+ if (sc->dev == NULL)
+ return (ENXIO);
+ device_set_softc(sc->dev, sc);
+ /*
+ * Don't set description here; devclass_add_driver() ->
+ * device_probe_child() -> device_set_driver() will nuke it again.
+ */
+ /* XXX ivars? */
+
+ pdev = device_get_parent(sc->dev);
+ KASSERT(pdev != NULL, ("%s: sc %p dev %p (%s) parent is NULL\n",
+ __func__, sc, sc->dev, device_get_nameunit(sc->dev)));
+ bus_devclass = device_get_devclass(pdev);
+ if (bus_devclass == NULL) {
+ printf("%s: Failed to get devclass from %s.\n", __func__,
+ device_get_nameunit(pdev));
+ return (ENXIO);
+ }
+
+ mtx_lock(&Giant);
+ error = devclass_add_driver(bus_devclass, &sdiob_driver,
+ BUS_PASS_DEFAULT, &sdiob_devclass);
+ mtx_unlock(&Giant);
+ if (error != 0) {
+ printf("%s: Failed to add driver to devclass: %d.\n",
+ __func__, error);
+ return (error);
+ }
+
+ /* Done. */
+ sc->nb_state = NB_STATE_SIM_ADDED;
+
+ return (0);
+}
+
+static void
+sdiobdiscover(void *context, int pending)
+{
+ struct cam_periph *periph;
+ struct sdiob_softc *sc;
+ int error;
+
+ KASSERT(context != NULL, ("%s: context is NULL\n", __func__));
+ periph = (struct cam_periph *)context;
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s\n", __func__));
+
+ /* Periph was held for us when this task was enqueued. */
+ if ((periph->flags & CAM_PERIPH_INVALID) != 0) {
+ cam_periph_release(periph);
+ return;
+ }
+
+ sc = periph->softc;
+ sc->sdio_state = SDIO_STATE_INITIALIZING;
+
+ if (sc->ccb == NULL)
+ sc->ccb = xpt_alloc_ccb();
+ else
+ memset(sc->ccb, 0, sizeof(*sc->ccb));
+ xpt_setup_ccb(&sc->ccb->ccb_h, periph->path, CAM_PRIORITY_NONE);
+
+ /*
+ * Read CCCR and FBR of each function, get manufacturer and device IDs,
+ * max block size, and whatever else we deem necessary.
+ */
+ cam_periph_lock(periph);
+ error = sdiob_get_card_info(sc);
+ if (error == 0)
+ sc->sdio_state = SDIO_STATE_READY;
+ else
+ sc->sdio_state = SDIO_STATE_DEAD;
+ cam_periph_unlock(periph);
+
+ if (error)
+ return;
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s: num_func %d\n",
+ __func__, sc->cardinfo.num_funcs));
+
+ /*
+ * Now CAM portion of the driver has been initialized and
+ * we know VID/PID of all the functions on the card.
+ * Time to hook into the newbus.
+ */
+ error = sdio_newbus_sim_add(sc);
+ if (error != 0)
+ sc->nb_state = NB_STATE_DEAD;
+
+ return;
+}
+
+/* Called at the end of cam_periph_alloc() for us to finish allocation. */
+static cam_status
+sdiobregister(struct cam_periph *periph, void *arg)
+{
+ struct sdiob_softc *sc;
+ int error;
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s: arg %p\n", __func__, arg));
+ if (arg == NULL) {
+ printf("%s: no getdev CCB, can't register device pariph %p\n",
+ __func__, periph);
+ return(CAM_REQ_CMP_ERR);
+ }
+ if (periph->sim == NULL || periph->sim->sim_dev == NULL) {
+ printf("%s: no sim %p or sim_dev %p\n", __func__, periph->sim,
+ (periph->sim != NULL) ? periph->sim->sim_dev : NULL);
+ return(CAM_REQ_CMP_ERR);
+ }
+
+ sc = (struct sdiob_softc *) malloc(sizeof(*sc), M_DEVBUF,
+ M_NOWAIT|M_ZERO);
+ if (sc == NULL) {
+ printf("%s: unable to allocate sc\n", __func__);
+ return (CAM_REQ_CMP_ERR);
+ }
+ sc->sdio_state = SDIO_STATE_DEAD;
+ sc->nb_state = NB_STATE_DEAD;
+ TASK_INIT(&sc->discover_task, 0, sdiobdiscover, periph);
+
+ /* Refcount until we are setup. Can't block. */
+ error = cam_periph_hold(periph, PRIBIO);
+ if (error != 0) {
+ printf("%s: lost periph during registration!\n", __func__);
+ free(sc, M_DEVBUF);
+ return(CAM_REQ_CMP_ERR);
+ }
+ periph->softc = sc;
+ sc->periph = periph;
+ cam_periph_unlock(periph);
+
+ error = taskqueue_enqueue(taskqueue_thread, &sc->discover_task);
+
+ cam_periph_lock(periph);
+ /* We will continue to hold a refcount for discover_task. */
+ /* cam_periph_unhold(periph); */
+
+ xpt_schedule(periph, CAM_PRIORITY_XPT);
+
+ return (CAM_REQ_CMP);
+}
+
+static void
+sdioboninvalidate(struct cam_periph *periph)
+{
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s:\n", __func__));
+
+ return;
+}
+
+static void
+sdiobcleanup(struct cam_periph *periph)
+{
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s:\n", __func__));
+
+ return;
+}
+
+static void
+sdiobstart(struct cam_periph *periph, union ccb *ccb)
+{
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s: ccb %p\n", __func__, ccb));
+
+ return;
+}
+
+static void
+sdiobasync(void *softc, uint32_t code, struct cam_path *path, void *arg)
+{
+ struct cam_periph *periph;
+ struct ccb_getdev *cgd;
+ cam_status status;
+
+ periph = (struct cam_periph *)softc;
+
+ CAM_DEBUG(path, CAM_DEBUG_TRACE, ("%s(code=%d)\n", __func__, code));
+ switch (code) {
+ case AC_FOUND_DEVICE:
+ if (arg == NULL)
+ break;
+ cgd = (struct ccb_getdev *)arg;
+ if (cgd->protocol != PROTO_MMCSD)
+ break;
+
+ /* We do not support SD memory (Combo) Cards. */
+ if ((path->device->mmc_ident_data.card_features &
+ CARD_FEATURE_MEMORY)) {
+ CAM_DEBUG(path, CAM_DEBUG_TRACE,
+ ("Memory card, not interested\n"));
+ break;
+ }
+
+ /*
+ * Allocate a peripheral instance for this device which starts
+ * the probe process.
+ */
+ status = cam_periph_alloc(sdiobregister, sdioboninvalidate,
+ sdiobcleanup, sdiobstart, SDIOB_NAME_S, CAM_PERIPH_BIO, path,
+ sdiobasync, AC_FOUND_DEVICE, cgd);
+ if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG)
+ CAM_DEBUG(path, CAM_DEBUG_PERIPH,
+ ("%s: Unable to attach to new device due to "
+ "status %#02x\n", __func__, status));
+ break;
+ default:
+ CAM_DEBUG(path, CAM_DEBUG_PERIPH,
+ ("%s: cannot handle async code %#02x\n", __func__, code));
+ cam_periph_async(periph, code, path, arg);
+ break;
+ }
+}
+
+static void
+sdiobinit(void)
+{
+ cam_status status;
+
+ /*
+ * Register for new device notification. We will be notified for all
+ * already existing ones.
+ */
+ status = xpt_register_async(AC_FOUND_DEVICE, sdiobasync, NULL, NULL);
+ if (status != CAM_REQ_CMP)
+ printf("%s: Failed to attach async callback, statux %#02x",
+ __func__, status);
+}
+
+/* This function will allow unloading the KLD. */
+static int
+sdiobdeinit(void)
+{
+
+ return (EOPNOTSUPP);
+}
+
+static struct periph_driver sdiobdriver =
+{
+ .init = sdiobinit,
+ .driver_name = SDIOB_NAME_S,
+ .units = TAILQ_HEAD_INITIALIZER(sdiobdriver.units),
+ .generation = 0,
+ .flags = 0,
+ .deinit = sdiobdeinit,
+};
+
+PERIPHDRIVER_DECLARE(SDIOB_NAME, sdiobdriver);
+MODULE_VERSION(SDIOB_NAME, 1);
Index: sys/dev/sdio/sdiodevs
===================================================================
--- /dev/null
+++ sys/dev/sdio/sdiodevs
@@ -0,0 +1,74 @@
+$FreeBSD$
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Take SDIO CIS, CISTPL_MANFID, TPLMID_MANF and TPLMID_CARD information and
+ * present them as vendor and device IDs (a terminology we understand for
+ * other parts) and run them through the usbdevs2h.awk script to generate
+ * a header file with #defines for them in sdiodevs.h and sdiodevs_data.h
+ * which provides a structure with a description as well.
+ * The format of this file is modelled after sys/dev/usb/usbdevs.
+ * For more details see there.
+ */
+
+/*
+ * --------------------------------------------------------------------------
+ * List of TPLMID_MANF "vendor ID"s.
+ * Please sort by vendor ID ascending.
+ */
+vendor BROADCOM 0x02d0 Broadcom
+vendor CYPRESS 0x02d0 Cypress/Broadcom
+
+/*
+ * --------------------------------------------------------------------------
+ * List of TPLMID_CARD "product ID"s.
+ * Please group by vendor in same order as above.
+ */
+
+/* Broadcom products */
+product BROADCOM 43241 0x4324 BCM43241 fullmac SDIO WiFi
+product BROADCOM 4329 0x4329 BCM4329 fullmac SDIO WiFi
+product BROADCOM 4330 0x4330 BCM4330 fullmac SDIO WiFi
+product BROADCOM 4334 0x4334 BCM4334 fullmac SDIO WiFi
+product BROADCOM 4335_4339 0x4335 BCM4335_4339 fullmac SDIO WiFi
+product BROADCOM 4339 0x4339 BCM4339 fullmac SDIO WiFi
+product BROADCOM 4345 0x4345 BCM4345 fullmac SDIO WiFi
+product BROADCOM 4354 0x4354 BCM4354 fullmac SDIO WiFi
+product BROADCOM 4356 0x4356 BCM4356 fullmac SDIO WiFi
+product BROADCOM 43143 0xa887 BCM43143 fullmac SDIO WiFi
+product BROADCOM 43340 0xa94c BCM43340 fullmac SDIO WiFi
+product BROADCOM 43341 0xa94d BCM43341 fullmac SDIO WiFi
+product BROADCOM 43362 0xa962 BCM43362 fullmac SDIO WiFi
+product BROADCOM 43364 0xa9a4 BCM43364 fullmac SDIO WiFi
+product BROADCOM 43430 0xa9a6 BCM43430 fullmac SDIO WiFi
+product BROADCOM 43455 0xa9bf BCM43455 fullmac SDIO WiFi
+product CYPRESS 4373 0x4373 CY4373 fullmac SDIO WiFi
+
+/* end */
Index: sys/modules/Makefile
===================================================================
--- sys/modules/Makefile
+++ sys/modules/Makefile
@@ -331,6 +331,7 @@
sdhci \
${_sdhci_acpi} \
sdhci_pci \
+ sdio \
sem \
send \
${_sf} \
Index: sys/modules/sdio/Makefile
===================================================================
--- /dev/null
+++ sys/modules/sdio/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/sdio
+
+KMOD= sdio
+SRCS= sdiob.c sdio_subr.c
+SRCS+= sdio_if.c
+SRCS+= device_if.h bus_if.h sdio_if.h
+
+.include <bsd.kmod.mk>
Index: sys/tools/usbdevs2h.awk
===================================================================
--- sys/tools/usbdevs2h.awk
+++ sys/tools/usbdevs2h.awk
@@ -36,7 +36,7 @@
function usage()
{
- print "usage: usbdevs2h.awk <srcfile> [-d|-h]";
+ print "usage: usbdevs2h.awk <srcfile> [-d|-h|-s|-S]";
exit 1;
}
@@ -51,7 +51,7 @@
printf(" */\n") > file
}
-function vendor(hfile)
+function vendor(hfile, type)
{
nvendors++
@@ -59,8 +59,8 @@
vendors[nvendors, 1] = $2; # name
vendors[nvendors, 2] = $3; # id
if (hfile)
- printf("#define\tUSB_VENDOR_%s\t%s\t", vendors[nvendors, 1],
- vendors[nvendors, 2]) > hfile
+ printf("#define\t%s_VENDOR_%s\t%s\t", toupper(type),
+ vendors[nvendors, 1], vendors[nvendors, 2]) > hfile
i = 3; f = 4;
# comments
@@ -101,7 +101,7 @@
printf("\n") > hfile
}
-function product(hfile)
+function product(hfile, type)
{
nproducts++
@@ -109,8 +109,9 @@
products[nproducts, 2] = $3; # product id
products[nproducts, 3] = $4; # id
if (hfile)
- printf("#define\tUSB_PRODUCT_%s_%s\t%s\t", \
- products[nproducts, 1], products[nproducts, 2], \
+ printf("#define\t%s_PRODUCT_%s_%s\t%s\t",
+ toupper(type),
+ products[nproducts, 1], products[nproducts, 2],
products[nproducts, 3]) > hfile
i=4; f = 5;
@@ -153,14 +154,16 @@
printf("\n") > hfile
}
-function dump_dfile(dfile)
+function dump_dfile(dfile, type)
{
printf("\n") > dfile
- printf("const struct usb_knowndev usb_knowndevs[] = {\n") > dfile
+ printf("const struct %s_knowndev %s_knowndevs[] = {\n",
+ tolower(type), tolower(type)) > dfile
for (i = 1; i <= nproducts; i++) {
printf("\t{\n") > dfile
- printf("\t USB_VENDOR_%s, USB_PRODUCT_%s_%s,\n",
- products[i, 1], products[i, 1], products[i, 2]) > dfile
+ printf("\t %s_VENDOR_%s, %s_PRODUCT_%s_%s,\n",
+ toupper(type), products[i, 1],
+ toupper(type), products[i, 1], products[i, 2]) > dfile
printf("\t ") > dfile
printf("0") > dfile
printf(",\n") > dfile
@@ -193,8 +196,9 @@
}
for (i = 1; i <= nvendors; i++) {
printf("\t{\n") > dfile
- printf("\t USB_VENDOR_%s, 0,\n", vendors[i, 1]) > dfile
- printf("\t USB_KNOWNDEV_NOPROD,\n") > dfile
+ printf("\t %s_VENDOR_%s, 0,\n",
+ toupper(type), vendors[i, 1]) > dfile
+ printf("\t %s_KNOWNDEV_NOPROD,\n", toupper(type)) > dfile
printf("\t \"") > dfile
j = 3;
needspace = 0;
@@ -216,15 +220,29 @@
BEGIN {
nproducts = nvendors = 0
+# Having a "/" in the #define should lead to an error later on.
+type="N/A"
# Process the command line
for (i = 1; i < ARGC; i++) {
arg = ARGV[i];
- if (arg !~ /^-[dh]+$/ && arg !~ /devs$/)
+ if (arg !~ /^-[dhsS]+$/ && arg !~ /devs$/)
usage();
- if (arg ~ /^-.*d/)
+ if (arg ~ /^-.*d/) {
dfile="usbdevs_data.h"
- if (arg ~ /^-.*h/)
+ type="USB"
+ }
+ if (arg ~ /^-.*h/) {
hfile="usbdevs.h"
+ type="USB"
+ }
+ if (arg ~ /^-.*S/) {
+ dfile="sdiodevs_data.h"
+ type="SDIO"
+ }
+ if (arg ~ /^-.*s/) {
+ hfile="sdiodevs.h"
+ type="SDIO"
+ }
if (arg ~ /devs$/)
srcfile = arg;
}
@@ -243,11 +261,11 @@
continue;
}
if ($1 == "vendor") {
- vendor(hfile)
+ vendor(hfile, type)
continue
}
if ($1 == "product") {
- product(hfile)
+ product(hfile, type)
continue
}
if ($0 == "")
@@ -261,5 +279,5 @@
# print out the match tables
if (dfile)
- dump_dfile(dfile)
+ dump_dfile(dfile, type)
}

File Metadata

Mime Type
text/plain
Expires
Thu, Sep 17, 8:25 AM (10 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29724524
Default Alt Text
D19749.1789633511.diff (54 KB)

Event Timeline