Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F149178120
D19749.1789633511.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
54 KB
Referenced Files
None
Subscribers
None
D19749.1789633511.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D19749: Add a CAM-Newbus SDIO support module.
Attached
Detach File
Event Timeline
Log In to Comment