Page MenuHomeFreeBSD

D12467.diff
No OneTemporary

D12467.diff

Index: sys/amd64/conf/GENERIC-MMCCAM
===================================================================
--- sys/amd64/conf/GENERIC-MMCCAM
+++ sys/amd64/conf/GENERIC-MMCCAM
@@ -34,3 +34,6 @@
# Add CAMDEBUG stuff
options CAMDEBUG
options CAM_DEBUG_FLAGS=(CAM_DEBUG_INFO|CAM_DEBUG_PROBE|CAM_DEBUG_PERIPH)
+
+# Newbus debugging
+options BUS_DEBUG
Index: sys/cam/cam_sim.h
===================================================================
--- sys/cam/cam_sim.h
+++ sys/cam/cam_sim.h
@@ -107,6 +107,7 @@
struct callout callout;
struct cam_devq *devq; /* Device Queue to use for this SIM */
int refcount; /* References to the SIM. */
+ device_t parent_dev; /* To export to attached peripherals */
};
#define CAM_SIM_LOCK(sim) mtx_lock((sim)->mtx)
Index: sys/cam/mmc/sdio_ivars.h
===================================================================
--- /dev/null
+++ sys/cam/mmc/sdio_ivars.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2006 Bernd Walter. All rights reserved.
+ * Copyright (c) 2006 M. Warner Losh. All rights reserved.
+ *
+ * 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.
+ *
+ * Portions of this software may have been developed with reference to
+ * the SD Simplified Specification. The following disclaimer may apply:
+ *
+ * The following conditions apply to the release of the simplified
+ * specification ("Simplified Specification") by the SD Card Association and
+ * the SD Group. The Simplified Specification is a subset of the complete SD
+ * Specification which is owned by the SD Card Association and the SD
+ * Group. This Simplified Specification is provided on a non-confidential
+ * basis subject to the disclaimers below. Any implementation of the
+ * Simplified Specification may require a license from the SD Card
+ * Association, SD Group, SD-3C LLC or other third parties.
+ *
+ * Disclaimers:
+ *
+ * The information contained in the Simplified Specification is presented only
+ * as a standard specification for SD Cards and SD Host/Ancillary products and
+ * is provided "AS-IS" without any representations or warranties of any
+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
+ * Card Association for any damages, any infringements of patents or other
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third
+ * parties, which may result from its use. No license is granted by
+ * implication, estoppel or otherwise under any patent or other rights of the
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
+ * or the SD Card Association to disclose or distribute any technical
+ * information, know-how or other confidential information to any third party.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef CAM_MMC_SDIO_IVARS_H
+#define CAM_MMC_SDIO_IVARS_H
+
+enum sdio_device_ivars {
+ SDIO_IVAR_VENDOR_ID,
+ SDIO_IVAR_PRODUCT_ID,
+};
+
+/*
+ * Simplified accessors for mmc devices
+ */
+#define SDIO_ACCESSOR(var, ivar, type) \
+ __BUS_ACCESSOR(sdio, var, SDIO, ivar, type)
+
+SDIO_ACCESSOR(vendor_id, VENDOR_ID, int)
+SDIO_ACCESSOR(product_id, PRODUCT_ID, int)
+
+#endif /* CAM_MMC_SDIO_IVARS_H */
Index: sys/dev/brcmwl/brcmwl.c
===================================================================
--- /dev/null
+++ sys/dev/brcmwl/brcmwl.c
@@ -0,0 +1,102 @@
+/*-
+ * Copyright (c) 2017 Ilya Bakulin. All rights reserved.
+ *
+ * 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/module.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/sysctl.h>
+
+#include <cam/mmc/sdio_ivars.h>
+
+#define SDIO_VENDOR_BROADCOM 0x02d0
+
+struct brcmwl_softc {
+ device_t dev;
+};
+
+static int brcmwl_probe(device_t dev);
+static int brcmwl_attach(device_t dev);
+static int brcmwl_detach(device_t dev);
+
+/*
+ * XXX Do we need to implement device_identify()?
+ */
+static int
+brcmwl_probe(device_t dev)
+{
+ int vendor_id;
+
+ device_printf(dev, "probe() called\n");
+ vendor_id = sdio_get_vendor_id(dev);
+ device_printf(dev, "vendor_id=%d\n", vendor_id);
+ if (vendor_id != SDIO_VENDOR_BROADCOM) {
+ device_printf(dev, "Non-Broadcom card\n");
+ return (-1);
+ }
+ return (BUS_PROBE_GENERIC);
+}
+
+static int
+brcmwl_attach(device_t dev)
+{
+ device_printf(dev, "attach() called\n");
+ device_set_desc(dev, "Imaginary SDIO WiFi driver");
+ return (0);
+}
+
+static int
+brcmwl_detach(device_t dev)
+{
+ return (0);
+}
+
+static device_method_t brcmwl_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, brcmwl_probe),
+ DEVMETHOD(device_attach, brcmwl_attach),
+ DEVMETHOD(device_detach, brcmwl_detach),
+
+ DEVMETHOD_END
+};
+
+static driver_t brcmwl_driver = {
+ "brcmwl",
+ brcmwl_methods,
+ sizeof(struct brcmwl_softc),
+};
+
+static devclass_t brcmwl_devclass;
+DRIVER_MODULE(brcmwl, sdio, brcmwl_driver, brcmwl_devclass, NULL, NULL);
Index: sys/dev/mmcnull/mmcnull.c
===================================================================
--- sys/dev/mmcnull/mmcnull.c
+++ sys/dev/mmcnull/mmcnull.c
@@ -120,6 +120,14 @@
device_get_unit(dev), &sc->sc_mtx, 1, 1,
sc->devq);
+ /*
+ * This is BAD and should be done another way!
+ * Changing cam_sim_alloc() to accept device_t instead of unit
+ * will be a good start, since it will be possible to call
+ * device_get_parent() and device_get_unit() inside cam_sim_alloc().
+ */
+ sc->sim->parent_dev = dev;
+
if (sc->sim == NULL) {
cam_simq_free(sc->devq);
device_printf(dev, "cannot allocate CAM SIM\n");
@@ -451,6 +459,11 @@
DEVMETHOD(device_probe, mmcnull_probe),
DEVMETHOD(device_attach, mmcnull_attach),
DEVMETHOD(device_detach, mmcnull_detach),
+ DEVMETHOD(device_detach, mmcnull_detach),
+
+ /* Bus interface */
+ DEVMETHOD(bus_add_child, bus_generic_add_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
DEVMETHOD_END
};
Index: sys/dev/sdio/sdio.c
===================================================================
--- /dev/null
+++ sys/dev/sdio/sdio.c
@@ -0,0 +1,492 @@
+/*-
+ * Copyright (c) 2017 Ilya Bakulin. All rights reserved.
+ *
+ * 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/module.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/sysctl.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 <cam/mmc/sdio_ivars.h>
+
+#include "sdio_subr.h"
+#include "opt_cam.h"
+
+struct sdio_softc {
+ device_t dev;
+ device_t card_dev;
+#define SDIO_STATE_INIT (0x1 << 1)
+#define SDIO_STATE_READY (0x1 << 2)
+ uint8_t state;
+
+ /*
+ * softc is used both in CAM and newbus, so we need to keep track
+ * which part is still alive.
+ * XXX Convert to a simple refcount field?
+ */
+ uint8_t is_cam_attached;
+ uint8_t is_newbus_attached;
+ struct task start_init_task;
+ struct card_info cinfo;
+};
+
+/* Peripheral driver methods */
+static periph_init_t sdioinit;
+static periph_deinit_t sdiodeinit;
+
+/* Peripheral device methods */
+static periph_ctor_t sdioregister;
+static periph_dtor_t sdiocleanup;
+static periph_start_t sdiostart;
+static periph_oninv_t sdiooninvalidate;
+
+static void sdio_identify(driver_t *, device_t);
+static void sdio_real_identify(driver_t *driver,
+ device_t parent,
+ struct sdio_softc *sc);
+static int sdio_probe(device_t);
+static int sdio_attach(device_t);
+static int sdio_detach(device_t);
+static int sdio_read_ivar(device_t dev, device_t child, int index,
+ uintptr_t *result);
+
+static void sdioasync(void *callback_arg, u_int32_t code,
+ struct cam_path *path, void *arg);
+
+static void sdio_start_init_task(void *context, int pending);
+
+static struct periph_driver sdiodriver =
+{
+ sdioinit, "sdio",
+ TAILQ_HEAD_INITIALIZER(sdiodriver.units),
+ /* generation */ 0,
+ /* flags */ 0,
+ sdiodeinit
+};
+
+PERIPHDRIVER_DECLARE(sdio, sdiodriver);
+static MALLOC_DEFINE(M_SDIO, "sdio", "sdio buffers");
+
+static device_method_t sdio_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, sdio_identify),
+ DEVMETHOD(device_probe, sdio_probe),
+ DEVMETHOD(device_attach, sdio_attach),
+ DEVMETHOD(device_detach, sdio_detach),
+
+ /* bus interface */
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
+ DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource),
+ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
+ DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
+ DEVMETHOD(bus_get_resource_list, bus_generic_get_resource_list),
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_add_child, bus_generic_add_child),
+ DEVMETHOD(bus_read_ivar, sdio_read_ivar),
+ DEVMETHOD(bus_write_ivar, bus_generic_write_ivar),
+
+ DEVMETHOD_END
+};
+
+driver_t sdio_driver = {
+ "sdio",
+ sdio_methods,
+ sizeof(struct sdio_softc),
+};
+
+static void
+sdioinit(void)
+{
+ cam_status status;
+ /*
+ * Install a global async callback. This callback will
+ * receive async callbacks like "new device found".
+ */
+ status = xpt_register_async(AC_FOUND_DEVICE, sdioasync, NULL, NULL);
+
+ if (status != CAM_REQ_CMP) {
+ printf("sdio: Failed to attach master async callback "
+ "due to status 0x%x!\n", status);
+ }
+}
+
+/* This function should just exist to allow unloading the KLD */
+static int
+sdiodeinit(void)
+{
+ struct cam_periph *periph, *periph_temp;
+
+ printf("CAM is calling sdiodeinit()\n");
+ /* Walk through all instances and invalidate them manually */
+ TAILQ_FOREACH_SAFE(periph, &sdiodriver.units, unit_links, periph_temp) {
+ cam_periph_lock(periph);
+ printf("Invalidating %s\n", periph->periph_name);
+ cam_periph_invalidate(periph);
+ }
+ return (0);
+}
+
+static cam_status
+sdioregister(struct cam_periph *periph, void *arg)
+{
+ struct sdio_softc *softc;
+ struct ccb_getdev *cgd;
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sdioregister\n"));
+ cgd = (struct ccb_getdev *)arg;
+ if (cgd == NULL) {
+ printf("sdioregister: no getdev CCB, can't register device\n");
+ return(CAM_REQ_CMP_ERR);
+ }
+
+ softc = (struct sdio_softc *)malloc(sizeof(*softc), M_DEVBUF,
+ M_NOWAIT|M_ZERO);
+
+ if (softc == NULL) {
+ printf("sdioregister: Unable to probe new device. "
+ "Unable to allocate softc\n");
+ return (CAM_REQ_CMP_ERR);
+ }
+
+ softc->state = SDIO_STATE_INIT;
+ softc->is_cam_attached = 1;
+
+ TASK_INIT(&softc->start_init_task, 0, sdio_start_init_task, periph);
+
+ periph->softc = softc;
+
+ xpt_schedule(periph, CAM_PRIORITY_XPT);
+ return (CAM_REQ_CMP);
+}
+
+static void
+sdioasync(void *callback_arg, u_int32_t code,
+ struct cam_path *path, void *arg)
+{
+ struct cam_periph *periph;
+ __unused struct sdio_softc *softc;
+
+ periph = (struct cam_periph *)callback_arg;
+ CAM_DEBUG(path, CAM_DEBUG_TRACE, ("sdioasync(code=%d)\n", code));
+ switch (code) {
+ case AC_FOUND_DEVICE: {
+ struct ccb_getdev *cgd;
+ cam_status status;
+
+ cgd = (struct ccb_getdev *)arg;
+ if (cgd == NULL)
+ break;
+
+ if (cgd->protocol != PROTO_MMCSD)
+ break;
+
+ /* We support only SDIO cards without memory portion */
+ 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 and start the probe
+ * process.
+ */
+ status = cam_periph_alloc(sdioregister, sdiooninvalidate,
+ sdiocleanup, sdiostart,
+ "sdio", CAM_PERIPH_BIO,
+ path, sdioasync,
+ AC_FOUND_DEVICE, cgd);
+
+ if (status != CAM_REQ_CMP
+ && status != CAM_REQ_INPROG)
+ CAM_DEBUG(path, CAM_DEBUG_PERIPH, ("sdioasync: Unable to attach to new device due to status 0x%x\n", status));
+ break;
+ }
+ default:
+ CAM_DEBUG(path, CAM_DEBUG_PERIPH, ("Cannot handle async code 0x%02x\n", code));
+ cam_periph_async(periph, code, path, arg);
+ break;
+ }
+}
+
+static void
+sdiooninvalidate(struct cam_periph *periph)
+{
+ struct sdio_softc *softc;
+
+ softc = (struct sdio_softc *)periph->softc;
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sdiooninvalidate\n"));
+
+ /*
+ * De-register any async callbacks.
+ */
+ xpt_register_async(0, sdioasync, periph, periph->path);
+}
+
+static void
+sdiocleanup(struct cam_periph *periph)
+{
+ struct sdio_softc *softc;
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sdiocleanup\n"));
+ softc = (struct sdio_softc *)periph->softc;
+ /*
+ * If newbus deallocation code has already run, destroy softc
+ * Otherwise just mark CAM as detached so that newbus detach
+ * is allowed to release the memory.
+ */
+ if (!softc->is_newbus_attached)
+ free(softc, M_DEVBUF);
+ else
+ softc->is_cam_attached = 0;
+ cam_periph_unlock(periph);
+}
+
+static void
+sdio_start_init_task(void *context, int pending) {
+ union ccb *new_ccb;
+ struct cam_periph *periph;
+ struct sdio_softc *softc;
+
+ periph = (struct cam_periph *)context;
+ softc = (struct sdio_softc *)periph->softc;
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sdio_start_init_task\n"));
+ /* periph was held for us when this task was enqueued */
+ if ((periph->flags & CAM_PERIPH_INVALID) != 0) {
+ cam_periph_release(periph);
+ return;
+ }
+ new_ccb = xpt_alloc_ccb();
+ xpt_setup_ccb(&new_ccb->ccb_h, periph->path,
+ CAM_PRIORITY_NONE);
+
+ cam_periph_lock(periph);
+
+ /*
+ * Read CCCR and FBR of each function, get manufacturer and device IDs,
+ * max block size, possibly more information like this that might be useful
+ */
+ get_sdio_card_info(new_ccb, &softc->cinfo);
+
+ softc->state = SDIO_STATE_READY;
+ cam_periph_unlock(periph);
+ xpt_free_ccb(new_ccb);
+
+ /*
+ * 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.
+ */
+ sdio_real_identify(&sdio_driver, periph->sim->parent_dev, softc);
+}
+
+static void
+sdiostart(struct cam_periph *periph, union ccb *start_ccb)
+{
+ struct sdio_softc *softc = (struct sdio_softc *)periph->softc;
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sdiostart\n"));
+
+ if (softc->state == SDIO_STATE_INIT) {
+ /* Make initialization */
+ taskqueue_enqueue(taskqueue_thread, &softc->start_init_task);
+ xpt_release_ccb(start_ccb);
+ } else
+ xpt_release_ccb(start_ccb);
+ return;
+}
+
+/*
+ * This is normally called by the parent bus.
+ * Thus, mmcnull calls us here. At this point we cannot really
+ * do anything, since even the card might not have been inserted yet.
+ *
+ * So the real work is done by sdio_real_identify().
+ * It's called by CAM peripheral device "sdio" when it has scanned
+ * the SDIO card registers and knows what functions are available
+ * on the card and their VIDs/PIDs.
+ * Since sdio_real_identify is called not during loading/unloading
+ * modules or newbus-related events, we have to initiate device
+ * probe/attach ourselves.
+ */
+static void
+sdio_identify(driver_t *driver, device_t parent)
+{
+ device_printf(parent, "sdio_identify() called\n");
+}
+
+static void
+sdio_real_identify(driver_t *driver, device_t parent, struct sdio_softc *sc) {
+ device_t child;
+ int ret;
+
+ if (resource_disabled("sdio", 0))
+ return;
+
+ device_printf(parent, "sdio_real_identify() called\n");
+ /* Avoid duplicates. */
+ if (device_find_child(parent, "sdio", -1)) {
+ device_printf(parent, "sdio_identify(): there is already a child\n");
+ return;
+ }
+
+ child = BUS_ADD_CHILD(parent, 20, "sdio", 0);
+ if (child == NULL) {
+ device_printf(parent, "add SDIO child failed\n");
+ return;
+ }
+
+ device_printf(parent, "BUS_ADD_CHILD() finished, child=%s\n",
+ device_get_nameunit(child));
+
+ device_set_desc(child, "SDIO bus");
+
+ /*
+ * Newbus stuff needs to be Giant-locked!
+ */
+ mtx_lock(&Giant);
+ ret = device_probe_and_attach(child);
+ mtx_unlock(&Giant);
+ if (ret != 0)
+ device_printf(child, "attach() failed, ret=%d", ret);
+ /*
+ * Now attach() has returned, so we can fill in the softc.
+ * We use device_set_softc() which sets a flag DF_EXTERNALSOFTC
+ * so that softc is not freed when the device detaches.
+ * This is just what we need since we manage softc from within
+ * the CAM code.
+ */
+ device_set_softc(child, sc);
+ sc->is_newbus_attached = 1;
+ sc->card_dev = bus_generic_add_child(child, 0, NULL, -1);
+ /*
+ * XXX If the brcmwl.ko was loaded before this code executes,
+ * it will not be probed/attached. But if it's loaded after,
+ * it is probed and attached just fine.
+ * Why?
+ */
+// bus_generic_attach(dev);
+}
+
+static int
+sdio_probe(device_t dev)
+{
+ device_printf(dev, "SDIO probe() called\n");
+ device_set_desc(dev, "SDIO bus");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+sdio_attach(device_t dev)
+{
+ device_printf(dev, "attached OK\n");
+ return (0);
+}
+
+static int
+sdio_detach(device_t dev)
+{
+ struct sdio_softc *sc;
+ int ret;
+
+ sc = device_get_softc(dev);
+ ret = device_delete_child(dev, sc->card_dev);
+ if (ret != 0) {
+ device_printf(dev, "Cannot detach child device %s: %d",
+ device_get_nameunit(sc->card_dev), ret);
+ }
+ sc->is_newbus_attached = 0;
+ if (!sc->is_cam_attached)
+ free(sc, M_DEVBUF);
+ device_printf(dev, "detached OK\n");
+ return (0);
+
+ /*
+ * This is not enough to delete the device from the tree!
+ * devinfo:
+ *
+ * isa0
+ * vga0
+ * mmcnull0
+ *
+ * But devinfo -v:
+ * isa0
+ * sc0
+ * vga0
+ * fdc0
+ * ppc0
+ * mmcnull0
+ * sdio0
+ */
+}
+
+static int
+sdio_read_ivar(device_t dev, device_t child, int index,
+ uintptr_t *result) {
+
+ device_printf(dev, "sdio_read_ivar(me, %s, %d)\n",
+ device_get_nameunit(child),
+ index);
+ switch (index) {
+ case SDIO_IVAR_VENDOR_ID:
+ *result = (int) 0xDEADBEEF;
+ break;
+ }
+ return (ENOENT);
+}
+
+devclass_t sdio_devclass;
+
+MODULE_VERSION(sdio, 1);
+
+/*
+ * As possible parent devclass we should also list sdhci.
+ * mmcnull doesn't extend sdhci so it stays on its own.
+ */
+DRIVER_MODULE(sdio, mmcnull, sdio_driver, sdio_devclass, 0, 0);
Index: sys/dev/sdio/sdio_subr.h
===================================================================
--- /dev/null
+++ sys/dev/sdio/sdio_subr.h
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2017 Ilya Bakulin. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _SDIO_SUBR_H_
+#define _SDIO_SUBR_H_
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <cam/cam.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_ccb.h>
+#include <cam/mmc/mmc_all.h>
+
+/*
+ * This file contains functions to work with SDIO cards.
+ * All non-static functions should be usable BOTH from
+ * the kernel and from the userland.
+*/
+
+struct cis_info {
+ uint16_t man_id;
+ uint16_t prod_id;
+ uint16_t max_block_size;
+};
+
+struct card_info {
+ uint8_t num_funcs;
+ struct cis_info f[8];
+};
+
+#ifdef _KERNEL
+uint8_t sdio_read_1(union ccb *ccb, uint8_t func_number, uint32_t addr, int *ret);
+uint32_t sdio_get_common_cis_addr(union ccb *ccb);
+int sdio_func_read_cis(union ccb *ccb, uint8_t func_number,
+ uint32_t cis_addr, struct cis_info *info);
+int get_sdio_card_info(union ccb *ccb, struct card_info *ci);
+#else /* _KERNEL */
+
+#endif /* _KERNEL */
+#endif /* _SDIO_SUBR_H_ */
Index: sys/dev/sdio/sdio_subr.c
===================================================================
--- /dev/null
+++ sys/dev/sdio/sdio_subr.c
@@ -0,0 +1,268 @@
+/*-
+ * Copyright (c) 2017 Ilya Bakulin. All rights reserved.
+ *
+ * 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$");
+
+/*
+ * This file contains functions to work with SDIO cards.
+ * All non-static functions should be useable BOTH from
+ * the kernel and from the userland.
+*/
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/sysctl.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 "sdio_subr.h"
+#include "opt_cam.h"
+
+#ifdef _KERNEL
+
+#define warnx(fmt, ...) CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_PERIPH, (fmt, ##__VA_ARGS__))
+
+/* CMD52: direct byte access */
+int sdio_rw_direct(union ccb *ccb,
+ uint8_t func_number,
+ uint32_t addr,
+ uint8_t is_write,
+ uint8_t *data,
+ uint8_t *resp);
+
+static int sdioerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags);
+
+int sdio_rw_direct(union ccb *ccb,
+ uint8_t func_number,
+ uint32_t addr,
+ uint8_t is_write,
+ uint8_t *data,
+ uint8_t *resp) {
+ struct ccb_mmcio *mmcio;
+ uint32_t flags;
+ uint32_t arg;
+ int retval = 0;
+
+ CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
+ ("sdio_mmcio_rw_direct(f=%d, wr=%d, addr=%02x, data=%02x)\n", func_number, is_write, addr, (data == NULL ? 0 : *data)));
+ mmcio = &ccb->mmcio;
+
+ flags = MMC_RSP_R5 | MMC_CMD_AC;
+ arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr);
+ if (is_write)
+ arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*data);
+ cam_fill_mmcio(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);
+
+ retval = cam_periph_runccb(ccb, sdioerror, CAM_FLAG_NONE, /*sense_flags*/0, NULL);
+ if (retval != 0)
+ return (retval);
+
+ /* TODO: Add handling of MMC errors */
+ *resp = ccb->mmcio.cmd.resp[0] & 0xFF;
+ return (0);
+}
+
+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, NULL));
+}
+
+uint8_t
+sdio_read_1(union ccb *ccb, uint8_t func_number, uint32_t addr, int *ret) {
+ uint8_t val;
+ *ret = sdio_rw_direct(ccb, func_number, addr, 0, NULL, &val);
+ return val;
+}
+
+int
+sdio_func_read_cis(union ccb *ccb, uint8_t func_number,
+ uint32_t cis_addr, struct cis_info *info) {
+ uint8_t tuple_id, tuple_len, tuple_count;
+ uint32_t addr;
+
+ char *cis1_info[4];
+ int start, i, ch, count, ret;
+ char cis1_info_buf[256];
+
+ tuple_count = 0; /* Use to prevent infinite loop in case of parse errors */
+ memset(cis1_info_buf, 0, 256);
+ do {
+ addr = cis_addr;
+ tuple_id = sdio_read_1(ccb, 0, addr++, &ret);
+ if (tuple_id == SD_IO_CISTPL_END)
+ break;
+ if (tuple_id == 0) {
+ cis_addr++;
+ continue;
+ }
+ tuple_len = sdio_read_1(ccb, 0, addr++, &ret);
+ if (tuple_len == 0 && tuple_id != 0x00) {
+ warnx("Parse error: 0-length tuple %02X\n", tuple_id);
+ return (-1);
+ }
+
+ switch (tuple_id) {
+ case SD_IO_CISTPL_VERS_1:
+ addr += 2;
+ for (count = 0, start = 0, i = 0;
+ (count < 4) && ((i + 4) < 256); i++) {
+ ch = sdio_read_1(ccb, 0, addr + i, &ret);
+ printf("count=%d, start=%d, i=%d, Got %c (0x%02x)\n", count, start, i, ch, ch);
+ if (ch == 0xff)
+ break;
+ cis1_info_buf[i] = ch;
+ if (ch == 0) {
+ cis1_info[count] =
+ cis1_info_buf + start;
+ start = i + 1;
+ count++;
+ }
+ }
+ 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:
+ info->man_id = sdio_read_1(ccb, 0, addr++, &ret);
+ info->man_id |= sdio_read_1(ccb, 0, addr++, &ret) << 8;
+
+ info->prod_id = sdio_read_1(ccb, 0, addr++, &ret);
+ info->prod_id |= sdio_read_1(ccb, 0, addr++, &ret) << 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("FUNCE is too short: %d\n", tuple_len);
+ break;
+ }
+ if (func_number == 0) {
+ /* skip extended_data */
+ addr++;
+ info->max_block_size = sdio_read_1(ccb, 0, addr++, &ret);
+ info->max_block_size |= sdio_read_1(ccb, 0, addr++, &ret) << 8;
+ } else {
+ info->max_block_size = sdio_read_1(ccb, 0, addr + 0xC, &ret);
+ info->max_block_size |= sdio_read_1(ccb, 0, addr + 0xD, &ret) << 8;
+ }
+ break;
+ default:
+ warnx("Skipping tuple ID %02X len %02X\n", tuple_id, tuple_len);
+ }
+ cis_addr += tuple_len + 2;
+ tuple_count++;
+ } while (tuple_count < 20);
+
+ return (0);
+}
+
+uint32_t
+sdio_get_common_cis_addr(union ccb *ccb) {
+ uint32_t addr;
+ int ret;
+
+ addr = sdio_read_1(ccb, 0, SD_IO_CCCR_CISPTR, &ret);
+ addr |= sdio_read_1(ccb, 0, SD_IO_CCCR_CISPTR + 1, &ret) << 8;
+ addr |= sdio_read_1(ccb, 0, SD_IO_CCCR_CISPTR + 2, &ret) << 16;
+ if (ret != 0) {
+ warnx("Failed to read CIS address\n");
+ return 0xFF;
+ }
+
+ if (addr < SD_IO_CIS_START || addr > SD_IO_CIS_START + SD_IO_CIS_SIZE) {
+ warnx("Bad CIS address: %04X\n", addr);
+ addr = 0xFF;
+ }
+
+ return addr;
+}
+
+int
+get_sdio_card_info(union ccb *ccb, struct card_info *ci) {
+ uint32_t cis_addr;
+ uint32_t fbr_addr;
+ int ret;
+
+ cis_addr = sdio_get_common_cis_addr(ccb);
+ if (cis_addr == 0xFF)
+ return (-1);
+
+ memset(ci, 0, sizeof(struct card_info));
+ ret = sdio_func_read_cis(ccb, 0, cis_addr, &ci->f[0]);
+ if (ret !=0)
+ return ret;
+ printf("F0: Vendor 0x%04X product 0x%04X max block size %d bytes\n",
+ ci->f[0].man_id, ci->f[0].prod_id, ci->f[0].max_block_size);
+
+
+ struct mmc_params *mmcp = &ccb->ccb_h.path->device->mmc_ident_data;
+ for (int i = 1; i <= mmcp->sdio_func_count; i++) {
+ fbr_addr = SD_IO_FBR_START * i + 0x9;
+ cis_addr = sdio_read_1(ccb, 0, fbr_addr++, &ret);
+ cis_addr |= sdio_read_1(ccb, 0, fbr_addr++, &ret) << 8;
+ cis_addr |= sdio_read_1(ccb, 0, fbr_addr++, &ret) << 16;
+ sdio_func_read_cis(ccb, i, cis_addr, &ci->f[i]);
+ printf("F%d: Vendor 0x%04X product 0x%04X max block size %d bytes\n",
+ i, ci->f[i].man_id, ci->f[i].prod_id, ci->f[i].max_block_size);
+ if (ci->f[i].man_id == 0) {
+ printf("F%d doesn't exist\n", i);
+ break;
+ }
+ ci->num_funcs++;
+ }
+
+ return (0);
+}
+
+#endif /* _KERNEL */
Index: sys/modules/brcmwl/Makefile
===================================================================
--- /dev/null
+++ sys/modules/brcmwl/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/brcmwl
+
+KMOD= brcmwl
+SRCS= brcmwl.c
+
+.include <bsd.kmod.mk>
Index: sys/modules/sdio/Makefile
===================================================================
--- /dev/null
+++ sys/modules/sdio/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/sdio
+
+KMOD= sdio
+SRCS= sdio.c sdio_subr.c device_if.h bus_if.h
+
+.include <bsd.kmod.mk>

File Metadata

Mime Type
text/plain
Expires
Sat, Jun 20, 5:50 PM (1 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34123641
Default Alt Text
D12467.diff (33 KB)

Event Timeline