Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F159936711
D12467.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
33 KB
Referenced Files
None
Subscribers
None
D12467.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D12467: Add sdio(4) peripheral device
Attached
Detach File
Event Timeline
Log In to Comment