xref: /freebsd/sys/dev/sdio/sdiob.c (revision 67ca7330cf34a789afbbff9ae7e4cdc4a4917ae3)
1*67ca7330SBjoern A. Zeeb /*-
2*67ca7330SBjoern A. Zeeb  * Copyright (c) 2017 Ilya Bakulin.  All rights reserved.
3*67ca7330SBjoern A. Zeeb  * Copyright (c) 2018-2019 The FreeBSD Foundation
4*67ca7330SBjoern A. Zeeb  *
5*67ca7330SBjoern A. Zeeb  * Portions of this software were developed by Björn Zeeb
6*67ca7330SBjoern A. Zeeb  * under sponsorship from the FreeBSD Foundation.
7*67ca7330SBjoern A. Zeeb  *
8*67ca7330SBjoern A. Zeeb  * Redistribution and use in source and binary forms, with or without
9*67ca7330SBjoern A. Zeeb  * modification, are permitted provided that the following conditions
10*67ca7330SBjoern A. Zeeb  * are met:
11*67ca7330SBjoern A. Zeeb  * 1. Redistributions of source code must retain the above copyright
12*67ca7330SBjoern A. Zeeb  *    notice, this list of conditions and the following disclaimer.
13*67ca7330SBjoern A. Zeeb  * 2. Redistributions in binary form must reproduce the above copyright
14*67ca7330SBjoern A. Zeeb  *    notice, this list of conditions and the following disclaimer in the
15*67ca7330SBjoern A. Zeeb  *    documentation and/or other materials provided with the distribution.
16*67ca7330SBjoern A. Zeeb  *
17*67ca7330SBjoern A. Zeeb  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18*67ca7330SBjoern A. Zeeb  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19*67ca7330SBjoern A. Zeeb  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20*67ca7330SBjoern A. Zeeb  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21*67ca7330SBjoern A. Zeeb  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22*67ca7330SBjoern A. Zeeb  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23*67ca7330SBjoern A. Zeeb  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24*67ca7330SBjoern A. Zeeb  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25*67ca7330SBjoern A. Zeeb  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26*67ca7330SBjoern A. Zeeb  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*67ca7330SBjoern A. Zeeb  *
28*67ca7330SBjoern A. Zeeb  *
29*67ca7330SBjoern A. Zeeb  * Portions of this software may have been developed with reference to
30*67ca7330SBjoern A. Zeeb  * the SD Simplified Specification.  The following disclaimer may apply:
31*67ca7330SBjoern A. Zeeb  *
32*67ca7330SBjoern A. Zeeb  * The following conditions apply to the release of the simplified
33*67ca7330SBjoern A. Zeeb  * specification ("Simplified Specification") by the SD Card Association and
34*67ca7330SBjoern A. Zeeb  * the SD Group. The Simplified Specification is a subset of the complete SD
35*67ca7330SBjoern A. Zeeb  * Specification which is owned by the SD Card Association and the SD
36*67ca7330SBjoern A. Zeeb  * Group. This Simplified Specification is provided on a non-confidential
37*67ca7330SBjoern A. Zeeb  * basis subject to the disclaimers below. Any implementation of the
38*67ca7330SBjoern A. Zeeb  * Simplified Specification may require a license from the SD Card
39*67ca7330SBjoern A. Zeeb  * Association, SD Group, SD-3C LLC or other third parties.
40*67ca7330SBjoern A. Zeeb  *
41*67ca7330SBjoern A. Zeeb  * Disclaimers:
42*67ca7330SBjoern A. Zeeb  *
43*67ca7330SBjoern A. Zeeb  * The information contained in the Simplified Specification is presented only
44*67ca7330SBjoern A. Zeeb  * as a standard specification for SD Cards and SD Host/Ancillary products and
45*67ca7330SBjoern A. Zeeb  * is provided "AS-IS" without any representations or warranties of any
46*67ca7330SBjoern A. Zeeb  * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
47*67ca7330SBjoern A. Zeeb  * Card Association for any damages, any infringements of patents or other
48*67ca7330SBjoern A. Zeeb  * right of the SD Group, SD-3C LLC, the SD Card Association or any third
49*67ca7330SBjoern A. Zeeb  * parties, which may result from its use. No license is granted by
50*67ca7330SBjoern A. Zeeb  * implication, estoppel or otherwise under any patent or other rights of the
51*67ca7330SBjoern A. Zeeb  * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
52*67ca7330SBjoern A. Zeeb  * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
53*67ca7330SBjoern A. Zeeb  * or the SD Card Association to disclose or distribute any technical
54*67ca7330SBjoern A. Zeeb  * information, know-how or other confidential information to any third party.
55*67ca7330SBjoern A. Zeeb  */
56*67ca7330SBjoern A. Zeeb /*
57*67ca7330SBjoern A. Zeeb  * Implements the (kernel specific) SDIO parts.
58*67ca7330SBjoern A. Zeeb  * This will hide all cam(4) functionality from the SDIO driver implementations
59*67ca7330SBjoern A. Zeeb  * which will just be newbus/device(9) and hence look like any other driver for,
60*67ca7330SBjoern A. Zeeb  * e.g., PCI.
61*67ca7330SBjoern A. Zeeb  * The sdiob(4) parts effetively "translate" between the two worlds "bridging"
62*67ca7330SBjoern A. Zeeb  * messages from MMCCAM to newbus and back.
63*67ca7330SBjoern A. Zeeb  */
64*67ca7330SBjoern A. Zeeb 
65*67ca7330SBjoern A. Zeeb #include <sys/cdefs.h>
66*67ca7330SBjoern A. Zeeb __FBSDID("$FreeBSD$");
67*67ca7330SBjoern A. Zeeb 
68*67ca7330SBjoern A. Zeeb #include "opt_cam.h"
69*67ca7330SBjoern A. Zeeb 
70*67ca7330SBjoern A. Zeeb #include <sys/param.h>
71*67ca7330SBjoern A. Zeeb #include <sys/systm.h>
72*67ca7330SBjoern A. Zeeb #include <sys/types.h>
73*67ca7330SBjoern A. Zeeb #include <sys/kernel.h>
74*67ca7330SBjoern A. Zeeb #include <sys/bus.h>
75*67ca7330SBjoern A. Zeeb #include <sys/endian.h>
76*67ca7330SBjoern A. Zeeb #include <sys/lock.h>
77*67ca7330SBjoern A. Zeeb #include <sys/malloc.h>
78*67ca7330SBjoern A. Zeeb #include <sys/module.h>
79*67ca7330SBjoern A. Zeeb #include <sys/mutex.h>
80*67ca7330SBjoern A. Zeeb 
81*67ca7330SBjoern A. Zeeb #include <cam/cam.h>
82*67ca7330SBjoern A. Zeeb #include <cam/cam_ccb.h>
83*67ca7330SBjoern A. Zeeb #include <cam/cam_queue.h>
84*67ca7330SBjoern A. Zeeb #include <cam/cam_periph.h>
85*67ca7330SBjoern A. Zeeb #include <cam/cam_xpt.h>
86*67ca7330SBjoern A. Zeeb #include <cam/cam_xpt_periph.h>
87*67ca7330SBjoern A. Zeeb #include <cam/cam_xpt_internal.h> /* for cam_path */
88*67ca7330SBjoern A. Zeeb #include <cam/cam_debug.h>
89*67ca7330SBjoern A. Zeeb 
90*67ca7330SBjoern A. Zeeb #include <dev/mmc/mmcreg.h>
91*67ca7330SBjoern A. Zeeb 
92*67ca7330SBjoern A. Zeeb #include <dev/sdio/sdiob.h>
93*67ca7330SBjoern A. Zeeb #include <dev/sdio/sdio_subr.h>
94*67ca7330SBjoern A. Zeeb 
95*67ca7330SBjoern A. Zeeb #include "sdio_if.h"
96*67ca7330SBjoern A. Zeeb 
97*67ca7330SBjoern A. Zeeb #ifdef DEBUG
98*67ca7330SBjoern A. Zeeb #define	DPRINTF(...)		printf(__VA_ARGS__)
99*67ca7330SBjoern A. Zeeb #define	DPRINTFDEV(_dev, ...)	device_printf((_dev), __VA_ARGS__)
100*67ca7330SBjoern A. Zeeb #else
101*67ca7330SBjoern A. Zeeb #define	DPRINTF(...)
102*67ca7330SBjoern A. Zeeb #define	DPRINTFDEV(_dev, ...)
103*67ca7330SBjoern A. Zeeb #endif
104*67ca7330SBjoern A. Zeeb 
105*67ca7330SBjoern A. Zeeb struct sdiob_softc {
106*67ca7330SBjoern A. Zeeb 	uint32_t			sdio_state;
107*67ca7330SBjoern A. Zeeb #define	SDIO_STATE_DEAD			0x0001
108*67ca7330SBjoern A. Zeeb #define	SDIO_STATE_INITIALIZING		0x0002
109*67ca7330SBjoern A. Zeeb #define	SDIO_STATE_READY		0x0004
110*67ca7330SBjoern A. Zeeb 	uint32_t			nb_state;
111*67ca7330SBjoern A. Zeeb #define	NB_STATE_DEAD			0x0001
112*67ca7330SBjoern A. Zeeb #define	NB_STATE_SIM_ADDED		0x0002
113*67ca7330SBjoern A. Zeeb #define	NB_STATE_READY			0x0004
114*67ca7330SBjoern A. Zeeb 
115*67ca7330SBjoern A. Zeeb 	/* CAM side (including sim_dev). */
116*67ca7330SBjoern A. Zeeb 	struct card_info		cardinfo;
117*67ca7330SBjoern A. Zeeb 	struct cam_periph		*periph;
118*67ca7330SBjoern A. Zeeb 	union ccb			*ccb;
119*67ca7330SBjoern A. Zeeb 	struct task			discover_task;
120*67ca7330SBjoern A. Zeeb 
121*67ca7330SBjoern A. Zeeb 	/* Newbus side. */
122*67ca7330SBjoern A. Zeeb 	device_t			dev;	/* Ourselves. */
123*67ca7330SBjoern A. Zeeb 	device_t			child[8];
124*67ca7330SBjoern A. Zeeb };
125*67ca7330SBjoern A. Zeeb 
126*67ca7330SBjoern A. Zeeb /* -------------------------------------------------------------------------- */
127*67ca7330SBjoern A. Zeeb /*
128*67ca7330SBjoern A. Zeeb  * SDIO CMD52 and CM53 implementations along with wrapper functions for
129*67ca7330SBjoern A. Zeeb  * read/write and a CAM periph helper function.
130*67ca7330SBjoern A. Zeeb  * These are the backend implementations of the sdio_if.m framework talking
131*67ca7330SBjoern A. Zeeb  * through CAM to sdhci.
132*67ca7330SBjoern A. Zeeb  * Note: these functions are also called during early discovery stage when
133*67ca7330SBjoern A. Zeeb  * we are not a device(9) yet. Hence they cannot always use device_printf()
134*67ca7330SBjoern A. Zeeb  * to log errors and have to call CAM_DEBUG() during these early stages.
135*67ca7330SBjoern A. Zeeb  */
136*67ca7330SBjoern A. Zeeb 
137*67ca7330SBjoern A. Zeeb static int
138*67ca7330SBjoern A. Zeeb sdioerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
139*67ca7330SBjoern A. Zeeb {
140*67ca7330SBjoern A. Zeeb 
141*67ca7330SBjoern A. Zeeb 	return (cam_periph_error(ccb, cam_flags, sense_flags));
142*67ca7330SBjoern A. Zeeb }
143*67ca7330SBjoern A. Zeeb 
144*67ca7330SBjoern A. Zeeb /* CMD52: direct byte access. */
145*67ca7330SBjoern A. Zeeb static int
146*67ca7330SBjoern A. Zeeb sdiob_rw_direct_sc(struct sdiob_softc *sc, uint8_t fn, uint32_t addr, bool wr,
147*67ca7330SBjoern A. Zeeb     uint8_t *val)
148*67ca7330SBjoern A. Zeeb {
149*67ca7330SBjoern A. Zeeb 	uint32_t arg, flags;
150*67ca7330SBjoern A. Zeeb 	int error;
151*67ca7330SBjoern A. Zeeb 
152*67ca7330SBjoern A. Zeeb 	KASSERT((val != NULL), ("%s val passed as NULL\n", __func__));
153*67ca7330SBjoern A. Zeeb 
154*67ca7330SBjoern A. Zeeb 	if (sc->ccb == NULL)
155*67ca7330SBjoern A. Zeeb 		sc->ccb = xpt_alloc_ccb();
156*67ca7330SBjoern A. Zeeb 	else
157*67ca7330SBjoern A. Zeeb 		memset(sc->ccb, 0, sizeof(*sc->ccb));
158*67ca7330SBjoern A. Zeeb 	xpt_setup_ccb(&sc->ccb->ccb_h, sc->periph->path, CAM_PRIORITY_NONE);
159*67ca7330SBjoern A. Zeeb 	CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_TRACE,
160*67ca7330SBjoern A. Zeeb 	    ("%s(fn=%d, addr=%#02x, wr=%d, *val=%#02x)\n", __func__,
161*67ca7330SBjoern A. Zeeb 	    fn, addr, wr, *val));
162*67ca7330SBjoern A. Zeeb 
163*67ca7330SBjoern A. Zeeb 	flags = MMC_RSP_R5 | MMC_CMD_AC;
164*67ca7330SBjoern A. Zeeb 	arg = SD_IO_RW_FUNC(fn) | SD_IO_RW_ADR(addr);
165*67ca7330SBjoern A. Zeeb 	if (wr)
166*67ca7330SBjoern A. Zeeb 		arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*val);
167*67ca7330SBjoern A. Zeeb 
168*67ca7330SBjoern A. Zeeb 	cam_fill_mmcio(&sc->ccb->mmcio,
169*67ca7330SBjoern A. Zeeb 		/*retries*/ 0,
170*67ca7330SBjoern A. Zeeb 		/*cbfcnp*/ NULL,
171*67ca7330SBjoern A. Zeeb 		/*flags*/ CAM_DIR_NONE,
172*67ca7330SBjoern A. Zeeb 		/*mmc_opcode*/ SD_IO_RW_DIRECT,
173*67ca7330SBjoern A. Zeeb 		/*mmc_arg*/ arg,
174*67ca7330SBjoern A. Zeeb 		/*mmc_flags*/ flags,
175*67ca7330SBjoern A. Zeeb 		/*mmc_data*/ 0,
176*67ca7330SBjoern A. Zeeb 		/*timeout*/ sc->cardinfo.f[fn].timeout);
177*67ca7330SBjoern A. Zeeb 	error = cam_periph_runccb(sc->ccb, sdioerror, CAM_FLAG_NONE, 0, NULL);
178*67ca7330SBjoern A. Zeeb 	if (error != 0) {
179*67ca7330SBjoern A. Zeeb 		if (sc->dev != NULL)
180*67ca7330SBjoern A. Zeeb 			device_printf(sc->dev,
181*67ca7330SBjoern A. Zeeb 			    "%s: Failed to %s address %#10x error=%d\n",
182*67ca7330SBjoern A. Zeeb 			    __func__, (wr) ? "write" : "read", addr, error);
183*67ca7330SBjoern A. Zeeb 		else
184*67ca7330SBjoern A. Zeeb 			CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_INFO,
185*67ca7330SBjoern A. Zeeb 			    ("%s: Failed to %s address: %#10x error=%d\n",
186*67ca7330SBjoern A. Zeeb 			    __func__, (wr) ? "write" : "read", addr, error));
187*67ca7330SBjoern A. Zeeb 		return (error);
188*67ca7330SBjoern A. Zeeb 	}
189*67ca7330SBjoern A. Zeeb 
190*67ca7330SBjoern A. Zeeb 	/* TODO: Add handling of MMC errors */
191*67ca7330SBjoern A. Zeeb 	/* ccb->mmcio.cmd.error ? */
192*67ca7330SBjoern A. Zeeb 	if (wr == false)
193*67ca7330SBjoern A. Zeeb 		*val = sc->ccb->mmcio.cmd.resp[0] & 0xff;
194*67ca7330SBjoern A. Zeeb 
195*67ca7330SBjoern A. Zeeb 	return (0);
196*67ca7330SBjoern A. Zeeb }
197*67ca7330SBjoern A. Zeeb 
198*67ca7330SBjoern A. Zeeb static int
199*67ca7330SBjoern A. Zeeb sdio_rw_direct(device_t dev, uint8_t fn, uint32_t addr, bool wr,
200*67ca7330SBjoern A. Zeeb     uint8_t *val)
201*67ca7330SBjoern A. Zeeb {
202*67ca7330SBjoern A. Zeeb 	struct sdiob_softc *sc;
203*67ca7330SBjoern A. Zeeb 	int error;
204*67ca7330SBjoern A. Zeeb 
205*67ca7330SBjoern A. Zeeb 	sc = device_get_softc(dev);
206*67ca7330SBjoern A. Zeeb 	cam_periph_lock(sc->periph);
207*67ca7330SBjoern A. Zeeb 	error = sdiob_rw_direct_sc(sc, fn, addr, wr, val);
208*67ca7330SBjoern A. Zeeb 	cam_periph_unlock(sc->periph);
209*67ca7330SBjoern A. Zeeb 	return (error);
210*67ca7330SBjoern A. Zeeb }
211*67ca7330SBjoern A. Zeeb 
212*67ca7330SBjoern A. Zeeb static int
213*67ca7330SBjoern A. Zeeb sdiob_read_direct(device_t dev, uint8_t fn, uint32_t addr, uint8_t *val)
214*67ca7330SBjoern A. Zeeb {
215*67ca7330SBjoern A. Zeeb 	int error;
216*67ca7330SBjoern A. Zeeb 	uint8_t v;
217*67ca7330SBjoern A. Zeeb 
218*67ca7330SBjoern A. Zeeb 	error = sdio_rw_direct(dev, fn, addr, false, &v);
219*67ca7330SBjoern A. Zeeb 	/* Be polite and do not touch the value on read error. */
220*67ca7330SBjoern A. Zeeb 	if (error == 0 && val != NULL)
221*67ca7330SBjoern A. Zeeb 		*val = v;
222*67ca7330SBjoern A. Zeeb 	return (error);
223*67ca7330SBjoern A. Zeeb }
224*67ca7330SBjoern A. Zeeb 
225*67ca7330SBjoern A. Zeeb static int
226*67ca7330SBjoern A. Zeeb sdiob_write_direct(device_t dev, uint8_t fn, uint32_t addr, uint8_t val)
227*67ca7330SBjoern A. Zeeb {
228*67ca7330SBjoern A. Zeeb 
229*67ca7330SBjoern A. Zeeb 	return (sdio_rw_direct(dev, fn, addr, true, &val));
230*67ca7330SBjoern A. Zeeb }
231*67ca7330SBjoern A. Zeeb 
232*67ca7330SBjoern A. Zeeb /*
233*67ca7330SBjoern A. Zeeb  * CMD53: IO_RW_EXTENDED, read and write multiple I/O registers.
234*67ca7330SBjoern A. Zeeb  * Increment false gets FIFO mode (single register address).
235*67ca7330SBjoern A. Zeeb  */
236*67ca7330SBjoern A. Zeeb /*
237*67ca7330SBjoern A. Zeeb  * A b_count of 0 means byte mode, b_count > 0 gets block mode.
238*67ca7330SBjoern A. Zeeb  * A b_count of >= 512 would mean infinitive block transfer, which would become
239*67ca7330SBjoern A. Zeeb  * b_count = 0, is not yet supported.
240*67ca7330SBjoern A. Zeeb  * For b_count == 0, blksz is the len of bytes, otherwise it is the amount of
241*67ca7330SBjoern A. Zeeb  * full sized blocks (you must not round the blocks up and leave the last one
242*67ca7330SBjoern A. Zeeb  * partial!)
243*67ca7330SBjoern A. Zeeb  * For byte mode, the maximum of blksz is the functions cur_blksize.
244*67ca7330SBjoern A. Zeeb  * This function should ever only be called by sdio_rw_extended_sc()!
245*67ca7330SBjoern A. Zeeb  */
246*67ca7330SBjoern A. Zeeb static int
247*67ca7330SBjoern A. Zeeb sdiob_rw_extended_cam(struct sdiob_softc *sc, uint8_t fn, uint32_t addr,
248*67ca7330SBjoern A. Zeeb     bool wr, uint8_t *buffer, bool incaddr, uint32_t b_count, uint16_t blksz)
249*67ca7330SBjoern A. Zeeb {
250*67ca7330SBjoern A. Zeeb 	struct mmc_data mmcd;
251*67ca7330SBjoern A. Zeeb 	uint32_t arg, cam_flags, flags, len;
252*67ca7330SBjoern A. Zeeb 	int error;
253*67ca7330SBjoern A. Zeeb 
254*67ca7330SBjoern A. Zeeb 	if (sc->ccb == NULL)
255*67ca7330SBjoern A. Zeeb 		sc->ccb = xpt_alloc_ccb();
256*67ca7330SBjoern A. Zeeb 	else
257*67ca7330SBjoern A. Zeeb 		memset(sc->ccb, 0, sizeof(*sc->ccb));
258*67ca7330SBjoern A. Zeeb 	xpt_setup_ccb(&sc->ccb->ccb_h, sc->periph->path, CAM_PRIORITY_NONE);
259*67ca7330SBjoern A. Zeeb 	CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_TRACE,
260*67ca7330SBjoern A. Zeeb 	    ("%s(fn=%d addr=%#0x wr=%d b_count=%u blksz=%u buf=%p incr=%d)\n",
261*67ca7330SBjoern A. Zeeb 	    __func__, fn, addr, wr, b_count, blksz, buffer, incaddr));
262*67ca7330SBjoern A. Zeeb 
263*67ca7330SBjoern A. Zeeb 	KASSERT((b_count <= 511), ("%s: infinitive block transfer not yet "
264*67ca7330SBjoern A. Zeeb 	    "supported: b_count %u blksz %u, sc %p, fn %u, addr %#10x, %s, "
265*67ca7330SBjoern A. Zeeb 	    "buffer %p, %s\n", __func__, b_count, blksz, sc, fn, addr,
266*67ca7330SBjoern A. Zeeb 	    wr ? "wr" : "rd", buffer, incaddr ? "incaddr" : "fifo"));
267*67ca7330SBjoern A. Zeeb 	/* Blksz needs to be within bounds for both byte and block mode! */
268*67ca7330SBjoern A. Zeeb 	KASSERT((blksz <= sc->cardinfo.f[fn].cur_blksize), ("%s: blksz "
269*67ca7330SBjoern A. Zeeb 	    "%u > bur_blksize %u, sc %p, fn %u, addr %#10x, %s, "
270*67ca7330SBjoern A. Zeeb 	    "buffer %p, %s, b_count %u\n", __func__, blksz,
271*67ca7330SBjoern A. Zeeb 	    sc->cardinfo.f[fn].cur_blksize, sc, fn, addr,
272*67ca7330SBjoern A. Zeeb 	    wr ? "wr" : "rd", buffer, incaddr ? "incaddr" : "fifo",
273*67ca7330SBjoern A. Zeeb 	    b_count));
274*67ca7330SBjoern A. Zeeb 	if (b_count == 0) {
275*67ca7330SBjoern A. Zeeb 		/* Byte mode */
276*67ca7330SBjoern A. Zeeb 		len = blksz;
277*67ca7330SBjoern A. Zeeb 		if (blksz == 512)
278*67ca7330SBjoern A. Zeeb 			blksz = 0;
279*67ca7330SBjoern A. Zeeb 		arg = SD_IOE_RW_LEN(blksz);
280*67ca7330SBjoern A. Zeeb 	} else {
281*67ca7330SBjoern A. Zeeb 		/* Block mode. */
282*67ca7330SBjoern A. Zeeb #ifdef __notyet__
283*67ca7330SBjoern A. Zeeb 		if (b_count > 511) {
284*67ca7330SBjoern A. Zeeb 			/* Infinitive block transfer. */
285*67ca7330SBjoern A. Zeeb 			b_count = 0;
286*67ca7330SBjoern A. Zeeb 		}
287*67ca7330SBjoern A. Zeeb #endif
288*67ca7330SBjoern A. Zeeb 		len = b_count * blksz;
289*67ca7330SBjoern A. Zeeb 		arg = SD_IOE_RW_BLK | SD_IOE_RW_LEN(b_count);
290*67ca7330SBjoern A. Zeeb 	}
291*67ca7330SBjoern A. Zeeb 
292*67ca7330SBjoern A. Zeeb 	flags = MMC_RSP_R5 | MMC_CMD_ADTC;
293*67ca7330SBjoern A. Zeeb 	arg |= SD_IOE_RW_FUNC(fn) | SD_IOE_RW_ADR(addr);
294*67ca7330SBjoern A. Zeeb 	if (incaddr)
295*67ca7330SBjoern A. Zeeb 		arg |= SD_IOE_RW_INCR;
296*67ca7330SBjoern A. Zeeb 
297*67ca7330SBjoern A. Zeeb 	memset(&mmcd, 0, sizeof(mmcd));
298*67ca7330SBjoern A. Zeeb 	mmcd.data = buffer;
299*67ca7330SBjoern A. Zeeb 	mmcd.len = len;
300*67ca7330SBjoern A. Zeeb 	if (arg & SD_IOE_RW_BLK) {
301*67ca7330SBjoern A. Zeeb 		/* XXX both should be known from elsewhere, aren't they? */
302*67ca7330SBjoern A. Zeeb 		mmcd.block_size = blksz;
303*67ca7330SBjoern A. Zeeb 		mmcd.block_count = b_count;
304*67ca7330SBjoern A. Zeeb 	}
305*67ca7330SBjoern A. Zeeb 
306*67ca7330SBjoern A. Zeeb 	if (wr) {
307*67ca7330SBjoern A. Zeeb 		arg |= SD_IOE_RW_WR;
308*67ca7330SBjoern A. Zeeb 		cam_flags = CAM_DIR_OUT;
309*67ca7330SBjoern A. Zeeb 		mmcd.flags = MMC_DATA_WRITE;
310*67ca7330SBjoern A. Zeeb 	} else {
311*67ca7330SBjoern A. Zeeb 		cam_flags = CAM_DIR_IN;
312*67ca7330SBjoern A. Zeeb 		mmcd.flags = MMC_DATA_READ;
313*67ca7330SBjoern A. Zeeb 	}
314*67ca7330SBjoern A. Zeeb #ifdef __notyet__
315*67ca7330SBjoern A. Zeeb 	if (b_count == 0) {
316*67ca7330SBjoern A. Zeeb 		/* XXX-BZ TODO FIXME.  Cancel I/O: CCCR -> ASx */
317*67ca7330SBjoern A. Zeeb 		/* Stop cmd. */
318*67ca7330SBjoern A. Zeeb 	}
319*67ca7330SBjoern A. Zeeb #endif
320*67ca7330SBjoern A. Zeeb 	cam_fill_mmcio(&sc->ccb->mmcio,
321*67ca7330SBjoern A. Zeeb 		/*retries*/ 0,
322*67ca7330SBjoern A. Zeeb 		/*cbfcnp*/ NULL,
323*67ca7330SBjoern A. Zeeb 		/*flags*/ cam_flags,
324*67ca7330SBjoern A. Zeeb 		/*mmc_opcode*/ SD_IO_RW_EXTENDED,
325*67ca7330SBjoern A. Zeeb 		/*mmc_arg*/ arg,
326*67ca7330SBjoern A. Zeeb 		/*mmc_flags*/ flags,
327*67ca7330SBjoern A. Zeeb 		/*mmc_data*/ &mmcd,
328*67ca7330SBjoern A. Zeeb 		/*timeout*/ sc->cardinfo.f[fn].timeout);
329*67ca7330SBjoern A. Zeeb 	if (arg & SD_IOE_RW_BLK) {
330*67ca7330SBjoern A. Zeeb 		mmcd.flags |= MMC_DATA_BLOCK_SIZE;
331*67ca7330SBjoern A. Zeeb 		if (b_count != 1)
332*67ca7330SBjoern A. Zeeb 			sc->ccb->mmcio.cmd.data->flags |= MMC_DATA_MULTI;
333*67ca7330SBjoern A. Zeeb 	}
334*67ca7330SBjoern A. Zeeb 
335*67ca7330SBjoern A. Zeeb 	/* Execute. */
336*67ca7330SBjoern A. Zeeb 	error = cam_periph_runccb(sc->ccb, sdioerror, CAM_FLAG_NONE, 0, NULL);
337*67ca7330SBjoern A. Zeeb 	if (error != 0) {
338*67ca7330SBjoern A. Zeeb 		if (sc->dev != NULL)
339*67ca7330SBjoern A. Zeeb 			device_printf(sc->dev,
340*67ca7330SBjoern A. Zeeb 			    "%s: Failed to %s address %#10x buffer %p size %u "
341*67ca7330SBjoern A. Zeeb 			    "%s b_count %u blksz %u error=%d\n",
342*67ca7330SBjoern A. Zeeb 			    __func__, (wr) ? "write to" : "read from", addr,
343*67ca7330SBjoern A. Zeeb 			    buffer, len, (incaddr) ? "incr" : "fifo",
344*67ca7330SBjoern A. Zeeb 			    b_count, blksz, error);
345*67ca7330SBjoern A. Zeeb 		else
346*67ca7330SBjoern A. Zeeb 			CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_INFO,
347*67ca7330SBjoern A. Zeeb 			    ("%s: Failed to %s address %#10x buffer %p size %u "
348*67ca7330SBjoern A. Zeeb 			    "%s b_count %u blksz %u error=%d\n",
349*67ca7330SBjoern A. Zeeb 			    __func__, (wr) ? "write to" : "read from", addr,
350*67ca7330SBjoern A. Zeeb 			    buffer, len, (incaddr) ? "incr" : "fifo",
351*67ca7330SBjoern A. Zeeb 			    b_count, blksz, error));
352*67ca7330SBjoern A. Zeeb 		return (error);
353*67ca7330SBjoern A. Zeeb 	}
354*67ca7330SBjoern A. Zeeb 
355*67ca7330SBjoern A. Zeeb 	/* TODO: Add handling of MMC errors */
356*67ca7330SBjoern A. Zeeb 	/* ccb->mmcio.cmd.error ? */
357*67ca7330SBjoern A. Zeeb 	error = sc->ccb->mmcio.cmd.resp[0] & 0xff;
358*67ca7330SBjoern A. Zeeb 	if (error != 0) {
359*67ca7330SBjoern A. Zeeb 		if (sc->dev != NULL)
360*67ca7330SBjoern A. Zeeb 			device_printf(sc->dev,
361*67ca7330SBjoern A. Zeeb 			    "%s: Failed to %s address %#10x buffer %p size %u "
362*67ca7330SBjoern A. Zeeb 			    "%s b_count %u blksz %u mmcio resp error=%d\n",
363*67ca7330SBjoern A. Zeeb 			    __func__, (wr) ? "write to" : "read from", addr,
364*67ca7330SBjoern A. Zeeb 			    buffer, len, (incaddr) ? "incr" : "fifo",
365*67ca7330SBjoern A. Zeeb 			    b_count, blksz, error);
366*67ca7330SBjoern A. Zeeb 		else
367*67ca7330SBjoern A. Zeeb 			CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_INFO,
368*67ca7330SBjoern A. Zeeb 			    ("%s: Failed to %s address %#10x buffer %p size %u "
369*67ca7330SBjoern A. Zeeb 			    "%s b_count %u blksz %u mmcio resp error=%d\n",
370*67ca7330SBjoern A. Zeeb 			    __func__, (wr) ? "write to" : "read from", addr,
371*67ca7330SBjoern A. Zeeb 			    buffer, len, (incaddr) ? "incr" : "fifo",
372*67ca7330SBjoern A. Zeeb 			    b_count, blksz, error));
373*67ca7330SBjoern A. Zeeb 	}
374*67ca7330SBjoern A. Zeeb 	return (error);
375*67ca7330SBjoern A. Zeeb }
376*67ca7330SBjoern A. Zeeb 
377*67ca7330SBjoern A. Zeeb static int
378*67ca7330SBjoern A. Zeeb sdiob_rw_extended_sc(struct sdiob_softc *sc, uint8_t fn, uint32_t addr,
379*67ca7330SBjoern A. Zeeb     bool wr, uint32_t size, uint8_t *buffer, bool incaddr)
380*67ca7330SBjoern A. Zeeb {
381*67ca7330SBjoern A. Zeeb 	int error;
382*67ca7330SBjoern A. Zeeb 	uint32_t len;
383*67ca7330SBjoern A. Zeeb 	uint32_t b_count;
384*67ca7330SBjoern A. Zeeb 
385*67ca7330SBjoern A. Zeeb 	/*
386*67ca7330SBjoern A. Zeeb 	 * If block mode is supported and we have at least 4 bytes to write and
387*67ca7330SBjoern A. Zeeb 	 * the size is at least one block, then start doing blk transfers.
388*67ca7330SBjoern A. Zeeb 	 */
389*67ca7330SBjoern A. Zeeb 	while (sc->cardinfo.support_multiblk &&
390*67ca7330SBjoern A. Zeeb 	    size > 4 && size >= sc->cardinfo.f[fn].cur_blksize) {
391*67ca7330SBjoern A. Zeeb 
392*67ca7330SBjoern A. Zeeb 		b_count = size / sc->cardinfo.f[fn].cur_blksize;
393*67ca7330SBjoern A. Zeeb 		KASSERT(b_count >= 1, ("%s: block count too small %u size %u "
394*67ca7330SBjoern A. Zeeb 		    "cur_blksize %u\n", __func__, b_count, size,
395*67ca7330SBjoern A. Zeeb 		    sc->cardinfo.f[fn].cur_blksize));
396*67ca7330SBjoern A. Zeeb 
397*67ca7330SBjoern A. Zeeb #ifdef __notyet__
398*67ca7330SBjoern A. Zeeb 		/* XXX support inifinite transfer with b_count = 0. */
399*67ca7330SBjoern A. Zeeb #else
400*67ca7330SBjoern A. Zeeb 		if (b_count > 511)
401*67ca7330SBjoern A. Zeeb 			b_count = 511;
402*67ca7330SBjoern A. Zeeb #endif
403*67ca7330SBjoern A. Zeeb 		len = b_count * sc->cardinfo.f[fn].cur_blksize;
404*67ca7330SBjoern A. Zeeb 		error = sdiob_rw_extended_cam(sc, fn, addr, wr, buffer, incaddr,
405*67ca7330SBjoern A. Zeeb 		    b_count, sc->cardinfo.f[fn].cur_blksize);
406*67ca7330SBjoern A. Zeeb 		if (error != 0)
407*67ca7330SBjoern A. Zeeb 			return (error);
408*67ca7330SBjoern A. Zeeb 
409*67ca7330SBjoern A. Zeeb 		size -= len;
410*67ca7330SBjoern A. Zeeb 		buffer += len;
411*67ca7330SBjoern A. Zeeb 		if (incaddr)
412*67ca7330SBjoern A. Zeeb 			addr += len;
413*67ca7330SBjoern A. Zeeb 	}
414*67ca7330SBjoern A. Zeeb 
415*67ca7330SBjoern A. Zeeb 	while (size > 0) {
416*67ca7330SBjoern A. Zeeb 		len = MIN(size, sc->cardinfo.f[fn].cur_blksize);
417*67ca7330SBjoern A. Zeeb 
418*67ca7330SBjoern A. Zeeb 		error = sdiob_rw_extended_cam(sc, fn, addr, wr, buffer, incaddr,
419*67ca7330SBjoern A. Zeeb 		    0, len);
420*67ca7330SBjoern A. Zeeb 		if (error != 0)
421*67ca7330SBjoern A. Zeeb 			return (error);
422*67ca7330SBjoern A. Zeeb 
423*67ca7330SBjoern A. Zeeb 		/* Prepare for next iteration. */
424*67ca7330SBjoern A. Zeeb 		size -= len;
425*67ca7330SBjoern A. Zeeb 		buffer += len;
426*67ca7330SBjoern A. Zeeb 		if (incaddr)
427*67ca7330SBjoern A. Zeeb 			addr += len;
428*67ca7330SBjoern A. Zeeb 	}
429*67ca7330SBjoern A. Zeeb 
430*67ca7330SBjoern A. Zeeb 	return (0);
431*67ca7330SBjoern A. Zeeb }
432*67ca7330SBjoern A. Zeeb 
433*67ca7330SBjoern A. Zeeb static int
434*67ca7330SBjoern A. Zeeb sdiob_rw_extended(device_t dev, uint8_t fn, uint32_t addr, bool wr,
435*67ca7330SBjoern A. Zeeb     uint32_t size, uint8_t *buffer, bool incaddr)
436*67ca7330SBjoern A. Zeeb {
437*67ca7330SBjoern A. Zeeb 	struct sdiob_softc *sc;
438*67ca7330SBjoern A. Zeeb 	int error;
439*67ca7330SBjoern A. Zeeb 
440*67ca7330SBjoern A. Zeeb 	sc = device_get_softc(dev);
441*67ca7330SBjoern A. Zeeb 	cam_periph_lock(sc->periph);
442*67ca7330SBjoern A. Zeeb 	error = sdiob_rw_extended_sc(sc, fn, addr, wr, size, buffer, incaddr);
443*67ca7330SBjoern A. Zeeb 	cam_periph_unlock(sc->periph);
444*67ca7330SBjoern A. Zeeb 	return (error);
445*67ca7330SBjoern A. Zeeb }
446*67ca7330SBjoern A. Zeeb 
447*67ca7330SBjoern A. Zeeb static int
448*67ca7330SBjoern A. Zeeb sdiob_read_extended(device_t dev, uint8_t fn, uint32_t addr, uint32_t size,
449*67ca7330SBjoern A. Zeeb     uint8_t *buffer, bool incaddr)
450*67ca7330SBjoern A. Zeeb {
451*67ca7330SBjoern A. Zeeb 
452*67ca7330SBjoern A. Zeeb 	return (sdiob_rw_extended(dev, fn, addr, false, size, buffer, incaddr));
453*67ca7330SBjoern A. Zeeb }
454*67ca7330SBjoern A. Zeeb 
455*67ca7330SBjoern A. Zeeb static int
456*67ca7330SBjoern A. Zeeb sdiob_write_extended(device_t dev, uint8_t fn, uint32_t addr, uint32_t size,
457*67ca7330SBjoern A. Zeeb     uint8_t *buffer, bool incaddr)
458*67ca7330SBjoern A. Zeeb {
459*67ca7330SBjoern A. Zeeb 
460*67ca7330SBjoern A. Zeeb 	return (sdiob_rw_extended(dev, fn, addr, true, size, buffer, incaddr));
461*67ca7330SBjoern A. Zeeb }
462*67ca7330SBjoern A. Zeeb 
463*67ca7330SBjoern A. Zeeb /* -------------------------------------------------------------------------- */
464*67ca7330SBjoern A. Zeeb /* Bus interface, ivars handling. */
465*67ca7330SBjoern A. Zeeb 
466*67ca7330SBjoern A. Zeeb static int
467*67ca7330SBjoern A. Zeeb sdiob_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
468*67ca7330SBjoern A. Zeeb {
469*67ca7330SBjoern A. Zeeb 	struct sdiob_softc *sc;
470*67ca7330SBjoern A. Zeeb 	struct sdio_func *f;
471*67ca7330SBjoern A. Zeeb 
472*67ca7330SBjoern A. Zeeb 	f = device_get_ivars(child);
473*67ca7330SBjoern A. Zeeb 	KASSERT(f != NULL, ("%s: dev %p child %p which %d, child ivars NULL\n",
474*67ca7330SBjoern A. Zeeb 	    __func__, dev, child, which));
475*67ca7330SBjoern A. Zeeb 
476*67ca7330SBjoern A. Zeeb 	switch (which) {
477*67ca7330SBjoern A. Zeeb 	case SDIOB_IVAR_SUPPORT_MULTIBLK:
478*67ca7330SBjoern A. Zeeb 		sc = device_get_softc(dev);
479*67ca7330SBjoern A. Zeeb 		KASSERT(sc != NULL, ("%s: dev %p child %p which %d, sc NULL\n",
480*67ca7330SBjoern A. Zeeb 		    __func__, dev, child, which));
481*67ca7330SBjoern A. Zeeb 		*result = sc->cardinfo.support_multiblk;
482*67ca7330SBjoern A. Zeeb 		break;
483*67ca7330SBjoern A. Zeeb 	case SDIOB_IVAR_FUNCTION:
484*67ca7330SBjoern A. Zeeb 		*result = (uintptr_t)f;
485*67ca7330SBjoern A. Zeeb 		break;
486*67ca7330SBjoern A. Zeeb 	case SDIOB_IVAR_FUNCNUM:
487*67ca7330SBjoern A. Zeeb 		*result = f->fn;
488*67ca7330SBjoern A. Zeeb 		break;
489*67ca7330SBjoern A. Zeeb 	case SDIOB_IVAR_CLASS:
490*67ca7330SBjoern A. Zeeb 		*result = f->class;
491*67ca7330SBjoern A. Zeeb 		break;
492*67ca7330SBjoern A. Zeeb 	case SDIOB_IVAR_VENDOR:
493*67ca7330SBjoern A. Zeeb 		*result = f->vendor;
494*67ca7330SBjoern A. Zeeb 		break;
495*67ca7330SBjoern A. Zeeb 	case SDIOB_IVAR_DEVICE:
496*67ca7330SBjoern A. Zeeb 		*result = f->device;
497*67ca7330SBjoern A. Zeeb 		break;
498*67ca7330SBjoern A. Zeeb 	case SDIOB_IVAR_DRVDATA:
499*67ca7330SBjoern A. Zeeb 		*result = f->drvdata;
500*67ca7330SBjoern A. Zeeb 		break;
501*67ca7330SBjoern A. Zeeb 	default:
502*67ca7330SBjoern A. Zeeb 		return (ENOENT);
503*67ca7330SBjoern A. Zeeb 	}
504*67ca7330SBjoern A. Zeeb 	return (0);
505*67ca7330SBjoern A. Zeeb }
506*67ca7330SBjoern A. Zeeb 
507*67ca7330SBjoern A. Zeeb static int
508*67ca7330SBjoern A. Zeeb sdiob_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
509*67ca7330SBjoern A. Zeeb {
510*67ca7330SBjoern A. Zeeb 	struct sdio_func *f;
511*67ca7330SBjoern A. Zeeb 
512*67ca7330SBjoern A. Zeeb 	f = device_get_ivars(child);
513*67ca7330SBjoern A. Zeeb 	KASSERT(f != NULL, ("%s: dev %p child %p which %d, child ivars NULL\n",
514*67ca7330SBjoern A. Zeeb 	    __func__, dev, child, which));
515*67ca7330SBjoern A. Zeeb 
516*67ca7330SBjoern A. Zeeb 	switch (which) {
517*67ca7330SBjoern A. Zeeb 	case SDIOB_IVAR_SUPPORT_MULTIBLK:
518*67ca7330SBjoern A. Zeeb 	case SDIOB_IVAR_FUNCTION:
519*67ca7330SBjoern A. Zeeb 	case SDIOB_IVAR_FUNCNUM:
520*67ca7330SBjoern A. Zeeb 	case SDIOB_IVAR_CLASS:
521*67ca7330SBjoern A. Zeeb 	case SDIOB_IVAR_VENDOR:
522*67ca7330SBjoern A. Zeeb 	case SDIOB_IVAR_DEVICE:
523*67ca7330SBjoern A. Zeeb 		return (EINVAL);	/* Disallowed. */
524*67ca7330SBjoern A. Zeeb 	case SDIOB_IVAR_DRVDATA:
525*67ca7330SBjoern A. Zeeb 		f->drvdata = value;
526*67ca7330SBjoern A. Zeeb 		break;
527*67ca7330SBjoern A. Zeeb 	default:
528*67ca7330SBjoern A. Zeeb 		return (ENOENT);
529*67ca7330SBjoern A. Zeeb 	}
530*67ca7330SBjoern A. Zeeb 
531*67ca7330SBjoern A. Zeeb 	return (0);
532*67ca7330SBjoern A. Zeeb }
533*67ca7330SBjoern A. Zeeb 
534*67ca7330SBjoern A. Zeeb 
535*67ca7330SBjoern A. Zeeb /* -------------------------------------------------------------------------- */
536*67ca7330SBjoern A. Zeeb /*
537*67ca7330SBjoern A. Zeeb  * Newbus functions for ourselves to probe/attach/detach and become a proper
538*67ca7330SBjoern A. Zeeb  * device(9).  Attach will also probe for child devices (another driver
539*67ca7330SBjoern A. Zeeb  * implementing SDIO).
540*67ca7330SBjoern A. Zeeb  */
541*67ca7330SBjoern A. Zeeb 
542*67ca7330SBjoern A. Zeeb static int
543*67ca7330SBjoern A. Zeeb sdiob_probe(device_t dev)
544*67ca7330SBjoern A. Zeeb {
545*67ca7330SBjoern A. Zeeb 
546*67ca7330SBjoern A. Zeeb 	device_set_desc(dev, "SDIO CAM-Newbus bridge");
547*67ca7330SBjoern A. Zeeb 	return (BUS_PROBE_DEFAULT);
548*67ca7330SBjoern A. Zeeb }
549*67ca7330SBjoern A. Zeeb 
550*67ca7330SBjoern A. Zeeb static int
551*67ca7330SBjoern A. Zeeb sdiob_attach(device_t dev)
552*67ca7330SBjoern A. Zeeb {
553*67ca7330SBjoern A. Zeeb 	struct sdiob_softc *sc;
554*67ca7330SBjoern A. Zeeb 	int error, i;
555*67ca7330SBjoern A. Zeeb 
556*67ca7330SBjoern A. Zeeb 	sc = device_get_softc(dev);
557*67ca7330SBjoern A. Zeeb 	if (sc == NULL)
558*67ca7330SBjoern A. Zeeb 		return (ENXIO);
559*67ca7330SBjoern A. Zeeb 
560*67ca7330SBjoern A. Zeeb 	/*
561*67ca7330SBjoern A. Zeeb 	 * Now that we are a dev, create one child device per function,
562*67ca7330SBjoern A. Zeeb 	 * initialize the backpointer, so we can pass them around and
563*67ca7330SBjoern A. Zeeb 	 * call CAM operations on the parent, and also set the function
564*67ca7330SBjoern A. Zeeb 	 * itself as ivars, so that we can query/update them.
565*67ca7330SBjoern A. Zeeb 	 * Do this before any child gets a chance to attach.
566*67ca7330SBjoern A. Zeeb 	 */
567*67ca7330SBjoern A. Zeeb 	for (i = 0; i < sc->cardinfo.num_funcs; i++) {
568*67ca7330SBjoern A. Zeeb 
569*67ca7330SBjoern A. Zeeb 		sc->child[i] = device_add_child(dev, NULL, -1);
570*67ca7330SBjoern A. Zeeb 		if (sc->child[i] == NULL) {
571*67ca7330SBjoern A. Zeeb 			device_printf(dev, "%s: failed to add child\n", __func__);
572*67ca7330SBjoern A. Zeeb 			return (ENXIO);
573*67ca7330SBjoern A. Zeeb 		}
574*67ca7330SBjoern A. Zeeb 		sc->cardinfo.f[i].dev = sc->child[i];
575*67ca7330SBjoern A. Zeeb 
576*67ca7330SBjoern A. Zeeb 		/* Set the function as ivar to the child device. */
577*67ca7330SBjoern A. Zeeb 		device_set_ivars(sc->child[i], &sc->cardinfo.f[i]);
578*67ca7330SBjoern A. Zeeb 	}
579*67ca7330SBjoern A. Zeeb 
580*67ca7330SBjoern A. Zeeb 	/*
581*67ca7330SBjoern A. Zeeb 	 * No one will ever attach to F0; we do the above to have a "device"
582*67ca7330SBjoern A. Zeeb 	 * to talk to in a general way in the code.
583*67ca7330SBjoern A. Zeeb 	 * Also do the probe/attach in a 2nd loop, so that all devices are
584*67ca7330SBjoern A. Zeeb 	 * present as we do have drivers consuming more than one device/func
585*67ca7330SBjoern A. Zeeb 	 * and might play "tricks" in order to do that assuming devices and
586*67ca7330SBjoern A. Zeeb 	 * ivars are available for all.
587*67ca7330SBjoern A. Zeeb 	 */
588*67ca7330SBjoern A. Zeeb 	for (i = 1; i < sc->cardinfo.num_funcs; i++) {
589*67ca7330SBjoern A. Zeeb 		error = device_probe_and_attach(sc->child[i]);
590*67ca7330SBjoern A. Zeeb 		if (error != 0 && bootverbose)
591*67ca7330SBjoern A. Zeeb 			device_printf(dev, "%s: device_probe_and_attach(%p %s) "
592*67ca7330SBjoern A. Zeeb 			    "failed %d for function %d, no child yet\n",
593*67ca7330SBjoern A. Zeeb 			     __func__,
594*67ca7330SBjoern A. Zeeb 			     sc->child, device_get_nameunit(sc->child[i]),
595*67ca7330SBjoern A. Zeeb 			     error, i);
596*67ca7330SBjoern A. Zeeb 	}
597*67ca7330SBjoern A. Zeeb 
598*67ca7330SBjoern A. Zeeb 	sc->nb_state = NB_STATE_READY;
599*67ca7330SBjoern A. Zeeb 
600*67ca7330SBjoern A. Zeeb 	cam_periph_lock(sc->periph);
601*67ca7330SBjoern A. Zeeb 	xpt_announce_periph(sc->periph, NULL);
602*67ca7330SBjoern A. Zeeb 	cam_periph_unlock(sc->periph);
603*67ca7330SBjoern A. Zeeb 
604*67ca7330SBjoern A. Zeeb 	return (0);
605*67ca7330SBjoern A. Zeeb }
606*67ca7330SBjoern A. Zeeb 
607*67ca7330SBjoern A. Zeeb static int
608*67ca7330SBjoern A. Zeeb sdiob_detach(device_t dev)
609*67ca7330SBjoern A. Zeeb {
610*67ca7330SBjoern A. Zeeb 
611*67ca7330SBjoern A. Zeeb 	/* XXX TODO? */
612*67ca7330SBjoern A. Zeeb 	return (EOPNOTSUPP);
613*67ca7330SBjoern A. Zeeb }
614*67ca7330SBjoern A. Zeeb 
615*67ca7330SBjoern A. Zeeb 
616*67ca7330SBjoern A. Zeeb /* -------------------------------------------------------------------------- */
617*67ca7330SBjoern A. Zeeb /*
618*67ca7330SBjoern A. Zeeb  * driver(9) and device(9) "control plane".
619*67ca7330SBjoern A. Zeeb  * This is what we use when we are making ourselves a device(9) in order to
620*67ca7330SBjoern A. Zeeb  * provide a newbus interface again, as well as the implementation of the
621*67ca7330SBjoern A. Zeeb  * SDIO interface.
622*67ca7330SBjoern A. Zeeb  */
623*67ca7330SBjoern A. Zeeb 
624*67ca7330SBjoern A. Zeeb static device_method_t sdiob_methods[] = {
625*67ca7330SBjoern A. Zeeb 
626*67ca7330SBjoern A. Zeeb 	/* Device interface. */
627*67ca7330SBjoern A. Zeeb 	DEVMETHOD(device_probe,		sdiob_probe),
628*67ca7330SBjoern A. Zeeb 	DEVMETHOD(device_attach,	sdiob_attach),
629*67ca7330SBjoern A. Zeeb 	DEVMETHOD(device_detach,	sdiob_detach),
630*67ca7330SBjoern A. Zeeb 
631*67ca7330SBjoern A. Zeeb 	/* Bus interface. */
632*67ca7330SBjoern A. Zeeb 	DEVMETHOD(bus_add_child,	bus_generic_add_child),
633*67ca7330SBjoern A. Zeeb 	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
634*67ca7330SBjoern A. Zeeb 	DEVMETHOD(bus_read_ivar,	sdiob_read_ivar),
635*67ca7330SBjoern A. Zeeb 	DEVMETHOD(bus_write_ivar,	sdiob_write_ivar),
636*67ca7330SBjoern A. Zeeb 
637*67ca7330SBjoern A. Zeeb 	/* SDIO interface. */
638*67ca7330SBjoern A. Zeeb 	DEVMETHOD(sdio_read_direct,	sdiob_read_direct),
639*67ca7330SBjoern A. Zeeb 	DEVMETHOD(sdio_write_direct,	sdiob_write_direct),
640*67ca7330SBjoern A. Zeeb 	DEVMETHOD(sdio_read_extended,	sdiob_read_extended),
641*67ca7330SBjoern A. Zeeb 	DEVMETHOD(sdio_write_extended,	sdiob_write_extended),
642*67ca7330SBjoern A. Zeeb 
643*67ca7330SBjoern A. Zeeb 	DEVMETHOD_END
644*67ca7330SBjoern A. Zeeb };
645*67ca7330SBjoern A. Zeeb 
646*67ca7330SBjoern A. Zeeb static devclass_t sdiob_devclass;
647*67ca7330SBjoern A. Zeeb static driver_t sdiob_driver = {
648*67ca7330SBjoern A. Zeeb 	SDIOB_NAME_S,
649*67ca7330SBjoern A. Zeeb 	sdiob_methods,
650*67ca7330SBjoern A. Zeeb 	0
651*67ca7330SBjoern A. Zeeb };
652*67ca7330SBjoern A. Zeeb 
653*67ca7330SBjoern A. Zeeb 
654*67ca7330SBjoern A. Zeeb /* -------------------------------------------------------------------------- */
655*67ca7330SBjoern A. Zeeb /*
656*67ca7330SBjoern A. Zeeb  * CIS related.
657*67ca7330SBjoern A. Zeeb  * Read card and function information and populate the cardinfo structure.
658*67ca7330SBjoern A. Zeeb  */
659*67ca7330SBjoern A. Zeeb 
660*67ca7330SBjoern A. Zeeb static int
661*67ca7330SBjoern A. Zeeb sdio_read_direct_sc(struct sdiob_softc *sc, uint8_t fn, uint32_t addr,
662*67ca7330SBjoern A. Zeeb     uint8_t *val)
663*67ca7330SBjoern A. Zeeb {
664*67ca7330SBjoern A. Zeeb 	int error;
665*67ca7330SBjoern A. Zeeb 	uint8_t v;
666*67ca7330SBjoern A. Zeeb 
667*67ca7330SBjoern A. Zeeb 	error = sdiob_rw_direct_sc(sc, fn, addr, false, &v);
668*67ca7330SBjoern A. Zeeb 	if (error == 0 && val != NULL)
669*67ca7330SBjoern A. Zeeb 		*val = v;
670*67ca7330SBjoern A. Zeeb 	return (error);
671*67ca7330SBjoern A. Zeeb }
672*67ca7330SBjoern A. Zeeb 
673*67ca7330SBjoern A. Zeeb static int
674*67ca7330SBjoern A. Zeeb sdio_func_read_cis(struct sdiob_softc *sc, uint8_t fn, uint32_t cis_addr)
675*67ca7330SBjoern A. Zeeb {
676*67ca7330SBjoern A. Zeeb 	char cis1_info_buf[256];
677*67ca7330SBjoern A. Zeeb 	char *cis1_info[4];
678*67ca7330SBjoern A. Zeeb 	int start, i, count, ret;
679*67ca7330SBjoern A. Zeeb 	uint32_t addr;
680*67ca7330SBjoern A. Zeeb 	uint8_t ch, tuple_id, tuple_len, tuple_count, v;
681*67ca7330SBjoern A. Zeeb 
682*67ca7330SBjoern A. Zeeb 	/* If we encounter any read errors, abort and return. */
683*67ca7330SBjoern A. Zeeb #define	ERR_OUT(ret)							\
684*67ca7330SBjoern A. Zeeb 	if (ret != 0)							\
685*67ca7330SBjoern A. Zeeb 		goto err;
686*67ca7330SBjoern A. Zeeb 	ret = 0;
687*67ca7330SBjoern A. Zeeb 	/* Use to prevent infinite loop in case of parse errors. */
688*67ca7330SBjoern A. Zeeb 	tuple_count = 0;
689*67ca7330SBjoern A. Zeeb 	memset(cis1_info_buf, 0, 256);
690*67ca7330SBjoern A. Zeeb 	do {
691*67ca7330SBjoern A. Zeeb 		addr = cis_addr;
692*67ca7330SBjoern A. Zeeb 		ret = sdio_read_direct_sc(sc, 0, addr++, &tuple_id);
693*67ca7330SBjoern A. Zeeb 		ERR_OUT(ret);
694*67ca7330SBjoern A. Zeeb 		if (tuple_id == SD_IO_CISTPL_END)
695*67ca7330SBjoern A. Zeeb 			break;
696*67ca7330SBjoern A. Zeeb 		if (tuple_id == 0) {
697*67ca7330SBjoern A. Zeeb 			cis_addr++;
698*67ca7330SBjoern A. Zeeb 			continue;
699*67ca7330SBjoern A. Zeeb 		}
700*67ca7330SBjoern A. Zeeb 		ret = sdio_read_direct_sc(sc, 0, addr++, &tuple_len);
701*67ca7330SBjoern A. Zeeb 		ERR_OUT(ret);
702*67ca7330SBjoern A. Zeeb 		if (tuple_len == 0) {
703*67ca7330SBjoern A. Zeeb 			CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_PERIPH,
704*67ca7330SBjoern A. Zeeb 			    ("%s: parse error: 0-length tuple %#02x\n",
705*67ca7330SBjoern A. Zeeb 			    __func__, tuple_id));
706*67ca7330SBjoern A. Zeeb 			return (EIO);
707*67ca7330SBjoern A. Zeeb 		}
708*67ca7330SBjoern A. Zeeb 
709*67ca7330SBjoern A. Zeeb 		switch (tuple_id) {
710*67ca7330SBjoern A. Zeeb 		case SD_IO_CISTPL_VERS_1:
711*67ca7330SBjoern A. Zeeb 			addr += 2;
712*67ca7330SBjoern A. Zeeb 			for (count = 0, start = 0, i = 0;
713*67ca7330SBjoern A. Zeeb 			     (count < 4) && ((i + 4) < 256); i++) {
714*67ca7330SBjoern A. Zeeb 				ret = sdio_read_direct_sc(sc, 0, addr + i, &ch);
715*67ca7330SBjoern A. Zeeb 				ERR_OUT(ret);
716*67ca7330SBjoern A. Zeeb 				DPRINTF("%s: count=%d, start=%d, i=%d, got "
717*67ca7330SBjoern A. Zeeb 				    "(%#02x)\n", __func__, count, start, i, ch);
718*67ca7330SBjoern A. Zeeb 				if (ch == 0xff)
719*67ca7330SBjoern A. Zeeb 					break;
720*67ca7330SBjoern A. Zeeb 				cis1_info_buf[i] = ch;
721*67ca7330SBjoern A. Zeeb 				if (ch == 0) {
722*67ca7330SBjoern A. Zeeb 					cis1_info[count] =
723*67ca7330SBjoern A. Zeeb 					    cis1_info_buf + start;
724*67ca7330SBjoern A. Zeeb 					start = i + 1;
725*67ca7330SBjoern A. Zeeb 					count++;
726*67ca7330SBjoern A. Zeeb 				}
727*67ca7330SBjoern A. Zeeb 			}
728*67ca7330SBjoern A. Zeeb 			DPRINTF("Card info: ");
729*67ca7330SBjoern A. Zeeb 			for (i=0; i < 4; i++)
730*67ca7330SBjoern A. Zeeb 				if (cis1_info[i])
731*67ca7330SBjoern A. Zeeb 					DPRINTF(" %s", cis1_info[i]);
732*67ca7330SBjoern A. Zeeb 			DPRINTF("\n");
733*67ca7330SBjoern A. Zeeb 			break;
734*67ca7330SBjoern A. Zeeb 		case SD_IO_CISTPL_MANFID:
735*67ca7330SBjoern A. Zeeb 			/* TPLMID_MANF */
736*67ca7330SBjoern A. Zeeb 			ret = sdio_read_direct_sc(sc, 0, addr++, &v);
737*67ca7330SBjoern A. Zeeb 			ERR_OUT(ret);
738*67ca7330SBjoern A. Zeeb 			sc->cardinfo.f[fn].vendor = v;
739*67ca7330SBjoern A. Zeeb 			ret = sdio_read_direct_sc(sc, 0, addr++, &v);
740*67ca7330SBjoern A. Zeeb 			ERR_OUT(ret);
741*67ca7330SBjoern A. Zeeb 			sc->cardinfo.f[fn].vendor |= (v << 8);
742*67ca7330SBjoern A. Zeeb 			/* TPLMID_CARD */
743*67ca7330SBjoern A. Zeeb 			ret = sdio_read_direct_sc(sc, 0, addr++, &v);
744*67ca7330SBjoern A. Zeeb 			ERR_OUT(ret);
745*67ca7330SBjoern A. Zeeb 			sc->cardinfo.f[fn].device = v;
746*67ca7330SBjoern A. Zeeb 			ret = sdio_read_direct_sc(sc, 0, addr, &v);
747*67ca7330SBjoern A. Zeeb 			ERR_OUT(ret);
748*67ca7330SBjoern A. Zeeb 			sc->cardinfo.f[fn].device |= (v << 8);
749*67ca7330SBjoern A. Zeeb 			break;
750*67ca7330SBjoern A. Zeeb 		case SD_IO_CISTPL_FUNCID:
751*67ca7330SBjoern A. Zeeb 			/* Not sure if we need to parse it? */
752*67ca7330SBjoern A. Zeeb 			break;
753*67ca7330SBjoern A. Zeeb 		case SD_IO_CISTPL_FUNCE:
754*67ca7330SBjoern A. Zeeb 			if (tuple_len < 4) {
755*67ca7330SBjoern A. Zeeb 				printf("%s: FUNCE is too short: %d\n",
756*67ca7330SBjoern A. Zeeb 				    __func__, tuple_len);
757*67ca7330SBjoern A. Zeeb 				break;
758*67ca7330SBjoern A. Zeeb 			}
759*67ca7330SBjoern A. Zeeb 			/* TPLFE_TYPE (Extended Data) */
760*67ca7330SBjoern A. Zeeb 			ret = sdio_read_direct_sc(sc, 0, addr++, &v);
761*67ca7330SBjoern A. Zeeb 			ERR_OUT(ret);
762*67ca7330SBjoern A. Zeeb 			if (fn == 0) {
763*67ca7330SBjoern A. Zeeb 				if (v != 0x00)
764*67ca7330SBjoern A. Zeeb 					break;
765*67ca7330SBjoern A. Zeeb 			} else {
766*67ca7330SBjoern A. Zeeb 				if (v != 0x01)
767*67ca7330SBjoern A. Zeeb 					break;
768*67ca7330SBjoern A. Zeeb 				addr += 0x0b;
769*67ca7330SBjoern A. Zeeb 			}
770*67ca7330SBjoern A. Zeeb 			ret = sdio_read_direct_sc(sc, 0, addr, &v);
771*67ca7330SBjoern A. Zeeb 			ERR_OUT(ret);
772*67ca7330SBjoern A. Zeeb 			sc->cardinfo.f[fn].max_blksize = v;
773*67ca7330SBjoern A. Zeeb 			ret = sdio_read_direct_sc(sc, 0, addr+1, &v);
774*67ca7330SBjoern A. Zeeb 			ERR_OUT(ret);
775*67ca7330SBjoern A. Zeeb 			sc->cardinfo.f[fn].max_blksize |= (v << 8);
776*67ca7330SBjoern A. Zeeb 			break;
777*67ca7330SBjoern A. Zeeb 		default:
778*67ca7330SBjoern A. Zeeb 			CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_PERIPH,
779*67ca7330SBjoern A. Zeeb 			    ("%s: Skipping fn %d tuple %d ID %#02x "
780*67ca7330SBjoern A. Zeeb 			    "len %#02x\n", __func__, fn, tuple_count,
781*67ca7330SBjoern A. Zeeb 			    tuple_id, tuple_len));
782*67ca7330SBjoern A. Zeeb 		}
783*67ca7330SBjoern A. Zeeb 		if (tuple_len == 0xff) {
784*67ca7330SBjoern A. Zeeb 			/* Also marks the end of a tuple chain (E1 16.2) */
785*67ca7330SBjoern A. Zeeb 			/* The tuple is valid, hence this going at the end. */
786*67ca7330SBjoern A. Zeeb 			break;
787*67ca7330SBjoern A. Zeeb 		}
788*67ca7330SBjoern A. Zeeb 		cis_addr += 2 + tuple_len;
789*67ca7330SBjoern A. Zeeb 		tuple_count++;
790*67ca7330SBjoern A. Zeeb 	} while (tuple_count < 20);
791*67ca7330SBjoern A. Zeeb err:
792*67ca7330SBjoern A. Zeeb #undef ERR_OUT
793*67ca7330SBjoern A. Zeeb 	return (ret);
794*67ca7330SBjoern A. Zeeb }
795*67ca7330SBjoern A. Zeeb 
796*67ca7330SBjoern A. Zeeb static int
797*67ca7330SBjoern A. Zeeb sdio_get_common_cis_addr(struct sdiob_softc *sc, uint32_t *addr)
798*67ca7330SBjoern A. Zeeb {
799*67ca7330SBjoern A. Zeeb 	int error;
800*67ca7330SBjoern A. Zeeb 	uint32_t a;
801*67ca7330SBjoern A. Zeeb 	uint8_t val;
802*67ca7330SBjoern A. Zeeb 
803*67ca7330SBjoern A. Zeeb 	error = sdio_read_direct_sc(sc, 0, SD_IO_CCCR_CISPTR + 0, &val);
804*67ca7330SBjoern A. Zeeb 	if (error != 0)
805*67ca7330SBjoern A. Zeeb 		goto err;
806*67ca7330SBjoern A. Zeeb 	a = val;
807*67ca7330SBjoern A. Zeeb 	error = sdio_read_direct_sc(sc, 0, SD_IO_CCCR_CISPTR + 1, &val);
808*67ca7330SBjoern A. Zeeb 	if (error != 0)
809*67ca7330SBjoern A. Zeeb 		goto err;
810*67ca7330SBjoern A. Zeeb 	a |= (val << 8);
811*67ca7330SBjoern A. Zeeb 	error = sdio_read_direct_sc(sc, 0, SD_IO_CCCR_CISPTR + 2, &val);
812*67ca7330SBjoern A. Zeeb 	if (error != 0)
813*67ca7330SBjoern A. Zeeb 		goto err;
814*67ca7330SBjoern A. Zeeb 	a |= (val << 16);
815*67ca7330SBjoern A. Zeeb 
816*67ca7330SBjoern A. Zeeb 	if (a < SD_IO_CIS_START || a > SD_IO_CIS_START + SD_IO_CIS_SIZE) {
817*67ca7330SBjoern A. Zeeb err:
818*67ca7330SBjoern A. Zeeb 		CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_PERIPH,
819*67ca7330SBjoern A. Zeeb 		    ("%s: bad CIS address: %#04x, error %d\n", __func__, a,
820*67ca7330SBjoern A. Zeeb 		    error));
821*67ca7330SBjoern A. Zeeb 	} else if (error == 0 && addr != NULL)
822*67ca7330SBjoern A. Zeeb 		*addr = a;
823*67ca7330SBjoern A. Zeeb 
824*67ca7330SBjoern A. Zeeb 	return (error);
825*67ca7330SBjoern A. Zeeb }
826*67ca7330SBjoern A. Zeeb 
827*67ca7330SBjoern A. Zeeb static int
828*67ca7330SBjoern A. Zeeb sdiob_get_card_info(struct sdiob_softc *sc)
829*67ca7330SBjoern A. Zeeb {
830*67ca7330SBjoern A. Zeeb 	struct mmc_params *mmcp;
831*67ca7330SBjoern A. Zeeb 	uint32_t cis_addr, fbr_addr;
832*67ca7330SBjoern A. Zeeb 	int fn, error;
833*67ca7330SBjoern A. Zeeb 	uint8_t fn_max, val;
834*67ca7330SBjoern A. Zeeb 
835*67ca7330SBjoern A. Zeeb 	error = sdio_get_common_cis_addr(sc, &cis_addr);
836*67ca7330SBjoern A. Zeeb 	if (error != 0)
837*67ca7330SBjoern A. Zeeb 		return (-1);
838*67ca7330SBjoern A. Zeeb 
839*67ca7330SBjoern A. Zeeb 	memset(&sc->cardinfo, 0, sizeof(sc->cardinfo));
840*67ca7330SBjoern A. Zeeb 
841*67ca7330SBjoern A. Zeeb 	/* F0 must always be present. */
842*67ca7330SBjoern A. Zeeb 	fn = 0;
843*67ca7330SBjoern A. Zeeb 	error = sdio_func_read_cis(sc, fn, cis_addr);
844*67ca7330SBjoern A. Zeeb 	if (error != 0)
845*67ca7330SBjoern A. Zeeb 		return (error);
846*67ca7330SBjoern A. Zeeb 	sc->cardinfo.num_funcs++;
847*67ca7330SBjoern A. Zeeb 	/* Read CCCR Card Capability. */
848*67ca7330SBjoern A. Zeeb 	error = sdio_read_direct_sc(sc, 0, SD_IO_CCCR_CARDCAP, &val);
849*67ca7330SBjoern A. Zeeb 	if (error != 0)
850*67ca7330SBjoern A. Zeeb 		return (error);
851*67ca7330SBjoern A. Zeeb 	sc->cardinfo.support_multiblk = (val & CCCR_CC_SMB) ? true : false;
852*67ca7330SBjoern A. Zeeb 	DPRINTF("%s: F%d: Vendor %#04x product %#04x max block size %d bytes "
853*67ca7330SBjoern A. Zeeb 	    "support_multiblk %s\n",
854*67ca7330SBjoern A. Zeeb 	    __func__, fn, sc->cardinfo.f[fn].vendor, sc->cardinfo.f[fn].device,
855*67ca7330SBjoern A. Zeeb 	    sc->cardinfo.f[fn].max_blksize,
856*67ca7330SBjoern A. Zeeb 	    sc->cardinfo.support_multiblk ? "yes" : "no");
857*67ca7330SBjoern A. Zeeb 
858*67ca7330SBjoern A. Zeeb 	/* mmcp->sdio_func_count contains the number of functions w/o F0. */
859*67ca7330SBjoern A. Zeeb 	mmcp = &sc->ccb->ccb_h.path->device->mmc_ident_data;
860*67ca7330SBjoern A. Zeeb 	fn_max = MIN(mmcp->sdio_func_count + 1, nitems(sc->cardinfo.f));
861*67ca7330SBjoern A. Zeeb 	for (fn = 1; fn < fn_max; fn++) {
862*67ca7330SBjoern A. Zeeb 
863*67ca7330SBjoern A. Zeeb 		fbr_addr = SD_IO_FBR_START * fn + SD_IO_FBR_CIS_OFFSET;
864*67ca7330SBjoern A. Zeeb 
865*67ca7330SBjoern A. Zeeb 		error = sdio_read_direct_sc(sc, 0, fbr_addr++, &val);
866*67ca7330SBjoern A. Zeeb 		if (error != 0)
867*67ca7330SBjoern A. Zeeb 			break;
868*67ca7330SBjoern A. Zeeb 		cis_addr = val;
869*67ca7330SBjoern A. Zeeb 		error = sdio_read_direct_sc(sc, 0, fbr_addr++, &val);
870*67ca7330SBjoern A. Zeeb 		if (error != 0)
871*67ca7330SBjoern A. Zeeb 			break;
872*67ca7330SBjoern A. Zeeb 		cis_addr |= (val << 8);
873*67ca7330SBjoern A. Zeeb 		error = sdio_read_direct_sc(sc, 0, fbr_addr++, &val);
874*67ca7330SBjoern A. Zeeb 		if (error != 0)
875*67ca7330SBjoern A. Zeeb 			break;
876*67ca7330SBjoern A. Zeeb 		cis_addr |= (val << 16);
877*67ca7330SBjoern A. Zeeb 
878*67ca7330SBjoern A. Zeeb 		error = sdio_func_read_cis(sc, fn, cis_addr);
879*67ca7330SBjoern A. Zeeb 		if (error != 0)
880*67ca7330SBjoern A. Zeeb 			break;
881*67ca7330SBjoern A. Zeeb 
882*67ca7330SBjoern A. Zeeb 		/* Read the Standard SDIO Function Interface Code. */
883*67ca7330SBjoern A. Zeeb 		fbr_addr = SD_IO_FBR_START * fn;
884*67ca7330SBjoern A. Zeeb 		error = sdio_read_direct_sc(sc, 0, fbr_addr++, &val);
885*67ca7330SBjoern A. Zeeb 		if (error != 0)
886*67ca7330SBjoern A. Zeeb 			break;
887*67ca7330SBjoern A. Zeeb 		sc->cardinfo.f[fn].class = (val & 0x0f);
888*67ca7330SBjoern A. Zeeb 		if (sc->cardinfo.f[fn].class == 0x0f) {
889*67ca7330SBjoern A. Zeeb 			error = sdio_read_direct_sc(sc, 0, fbr_addr, &val);
890*67ca7330SBjoern A. Zeeb 			if (error != 0)
891*67ca7330SBjoern A. Zeeb 				break;
892*67ca7330SBjoern A. Zeeb 			sc->cardinfo.f[fn].class = val;
893*67ca7330SBjoern A. Zeeb 		}
894*67ca7330SBjoern A. Zeeb 
895*67ca7330SBjoern A. Zeeb 		sc->cardinfo.f[fn].fn = fn;
896*67ca7330SBjoern A. Zeeb 		sc->cardinfo.f[fn].cur_blksize = sc->cardinfo.f[fn].max_blksize;
897*67ca7330SBjoern A. Zeeb 		sc->cardinfo.f[fn].retries = 0;
898*67ca7330SBjoern A. Zeeb 		sc->cardinfo.f[fn].timeout = 5000;
899*67ca7330SBjoern A. Zeeb 
900*67ca7330SBjoern A. Zeeb 		DPRINTF("%s: F%d: Class %d Vendor %#04x product %#04x "
901*67ca7330SBjoern A. Zeeb 		    "max_blksize %d bytes\n", __func__, fn,
902*67ca7330SBjoern A. Zeeb 		    sc->cardinfo.f[fn].class,
903*67ca7330SBjoern A. Zeeb 		    sc->cardinfo.f[fn].vendor, sc->cardinfo.f[fn].device,
904*67ca7330SBjoern A. Zeeb 		    sc->cardinfo.f[fn].max_blksize);
905*67ca7330SBjoern A. Zeeb 		if (sc->cardinfo.f[fn].vendor == 0) {
906*67ca7330SBjoern A. Zeeb 			DPRINTF("%s: F%d doesn't exist\n", __func__, fn);
907*67ca7330SBjoern A. Zeeb 			break;
908*67ca7330SBjoern A. Zeeb 		}
909*67ca7330SBjoern A. Zeeb 		sc->cardinfo.num_funcs++;
910*67ca7330SBjoern A. Zeeb 	}
911*67ca7330SBjoern A. Zeeb 	return (error);
912*67ca7330SBjoern A. Zeeb }
913*67ca7330SBjoern A. Zeeb 
914*67ca7330SBjoern A. Zeeb 
915*67ca7330SBjoern A. Zeeb /* -------------------------------------------------------------------------- */
916*67ca7330SBjoern A. Zeeb /*
917*67ca7330SBjoern A. Zeeb  * CAM periph registration, allocation, and detached from that a discovery
918*67ca7330SBjoern A. Zeeb  * task, which goes off reads cardinfo, and then adds ourselves to our SIM's
919*67ca7330SBjoern A. Zeeb  * device adding the devclass and registering the driver.  This keeps the
920*67ca7330SBjoern A. Zeeb  * newbus chain connected though we will talk CAM in the middle (until one
921*67ca7330SBjoern A. Zeeb  * day CAM might be newbusyfied).
922*67ca7330SBjoern A. Zeeb  */
923*67ca7330SBjoern A. Zeeb 
924*67ca7330SBjoern A. Zeeb static int
925*67ca7330SBjoern A. Zeeb sdio_newbus_sim_add(struct sdiob_softc *sc)
926*67ca7330SBjoern A. Zeeb {
927*67ca7330SBjoern A. Zeeb 	device_t pdev;
928*67ca7330SBjoern A. Zeeb 	devclass_t bus_devclass;
929*67ca7330SBjoern A. Zeeb 	int error;
930*67ca7330SBjoern A. Zeeb 
931*67ca7330SBjoern A. Zeeb 	/* Add ourselves to our parent (SIM) device. */
932*67ca7330SBjoern A. Zeeb 
933*67ca7330SBjoern A. Zeeb 	/* Add ourselves to our parent. That way we can become a parent. */
934*67ca7330SBjoern A. Zeeb 	KASSERT(sc->periph->sim->sim_dev != NULL, ("%s: sim_dev is NULL, sc %p "
935*67ca7330SBjoern A. Zeeb 	    "periph %p sim %p\n", __func__, sc, sc->periph, sc->periph->sim));
936*67ca7330SBjoern A. Zeeb 
937*67ca7330SBjoern A. Zeeb 	if (sc->dev == NULL)
938*67ca7330SBjoern A. Zeeb 		sc->dev = BUS_ADD_CHILD(sc->periph->sim->sim_dev, 0,
939*67ca7330SBjoern A. Zeeb 		    SDIOB_NAME_S, -1);
940*67ca7330SBjoern A. Zeeb 	if (sc->dev == NULL)
941*67ca7330SBjoern A. Zeeb 		return (ENXIO);
942*67ca7330SBjoern A. Zeeb 	device_set_softc(sc->dev, sc);
943*67ca7330SBjoern A. Zeeb 	/*
944*67ca7330SBjoern A. Zeeb 	 * Don't set description here; devclass_add_driver() ->
945*67ca7330SBjoern A. Zeeb 	 * device_probe_child() -> device_set_driver() will nuke it again.
946*67ca7330SBjoern A. Zeeb 	 */
947*67ca7330SBjoern A. Zeeb 
948*67ca7330SBjoern A. Zeeb 	pdev = device_get_parent(sc->dev);
949*67ca7330SBjoern A. Zeeb 	KASSERT(pdev != NULL, ("%s: sc %p dev %p (%s) parent is NULL\n",
950*67ca7330SBjoern A. Zeeb 	    __func__, sc, sc->dev, device_get_nameunit(sc->dev)));
951*67ca7330SBjoern A. Zeeb 	bus_devclass = device_get_devclass(pdev);
952*67ca7330SBjoern A. Zeeb 	if (bus_devclass == NULL) {
953*67ca7330SBjoern A. Zeeb 		printf("%s: Failed to get devclass from %s.\n", __func__,
954*67ca7330SBjoern A. Zeeb 		    device_get_nameunit(pdev));
955*67ca7330SBjoern A. Zeeb 		return (ENXIO);
956*67ca7330SBjoern A. Zeeb 	}
957*67ca7330SBjoern A. Zeeb 
958*67ca7330SBjoern A. Zeeb 	mtx_lock(&Giant);
959*67ca7330SBjoern A. Zeeb 	error = devclass_add_driver(bus_devclass, &sdiob_driver,
960*67ca7330SBjoern A. Zeeb 	    BUS_PASS_DEFAULT, &sdiob_devclass);
961*67ca7330SBjoern A. Zeeb 	mtx_unlock(&Giant);
962*67ca7330SBjoern A. Zeeb 	if (error != 0) {
963*67ca7330SBjoern A. Zeeb 		printf("%s: Failed to add driver to devclass: %d.\n",
964*67ca7330SBjoern A. Zeeb 		    __func__, error);
965*67ca7330SBjoern A. Zeeb 		return (error);
966*67ca7330SBjoern A. Zeeb 	}
967*67ca7330SBjoern A. Zeeb 
968*67ca7330SBjoern A. Zeeb 	/* Done. */
969*67ca7330SBjoern A. Zeeb 	sc->nb_state = NB_STATE_SIM_ADDED;
970*67ca7330SBjoern A. Zeeb 
971*67ca7330SBjoern A. Zeeb 	return (0);
972*67ca7330SBjoern A. Zeeb }
973*67ca7330SBjoern A. Zeeb 
974*67ca7330SBjoern A. Zeeb static void
975*67ca7330SBjoern A. Zeeb sdiobdiscover(void *context, int pending)
976*67ca7330SBjoern A. Zeeb {
977*67ca7330SBjoern A. Zeeb 	struct cam_periph *periph;
978*67ca7330SBjoern A. Zeeb 	struct sdiob_softc *sc;
979*67ca7330SBjoern A. Zeeb 	int error;
980*67ca7330SBjoern A. Zeeb 
981*67ca7330SBjoern A. Zeeb 	KASSERT(context != NULL, ("%s: context is NULL\n", __func__));
982*67ca7330SBjoern A. Zeeb 	periph = (struct cam_periph *)context;
983*67ca7330SBjoern A. Zeeb 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s\n", __func__));
984*67ca7330SBjoern A. Zeeb 
985*67ca7330SBjoern A. Zeeb 	/* Periph was held for us when this task was enqueued. */
986*67ca7330SBjoern A. Zeeb 	if ((periph->flags & CAM_PERIPH_INVALID) != 0) {
987*67ca7330SBjoern A. Zeeb 		cam_periph_release(periph);
988*67ca7330SBjoern A. Zeeb 		return;
989*67ca7330SBjoern A. Zeeb 	}
990*67ca7330SBjoern A. Zeeb 
991*67ca7330SBjoern A. Zeeb 	sc = periph->softc;
992*67ca7330SBjoern A. Zeeb 	sc->sdio_state = SDIO_STATE_INITIALIZING;
993*67ca7330SBjoern A. Zeeb 
994*67ca7330SBjoern A. Zeeb 	if (sc->ccb == NULL)
995*67ca7330SBjoern A. Zeeb 		sc->ccb = xpt_alloc_ccb();
996*67ca7330SBjoern A. Zeeb 	else
997*67ca7330SBjoern A. Zeeb 		memset(sc->ccb, 0, sizeof(*sc->ccb));
998*67ca7330SBjoern A. Zeeb 	xpt_setup_ccb(&sc->ccb->ccb_h, periph->path, CAM_PRIORITY_NONE);
999*67ca7330SBjoern A. Zeeb 
1000*67ca7330SBjoern A. Zeeb 	/*
1001*67ca7330SBjoern A. Zeeb 	 * Read CCCR and FBR of each function, get manufacturer and device IDs,
1002*67ca7330SBjoern A. Zeeb 	 * max block size, and whatever else we deem necessary.
1003*67ca7330SBjoern A. Zeeb 	 */
1004*67ca7330SBjoern A. Zeeb 	cam_periph_lock(periph);
1005*67ca7330SBjoern A. Zeeb 	error = sdiob_get_card_info(sc);
1006*67ca7330SBjoern A. Zeeb 	if  (error == 0)
1007*67ca7330SBjoern A. Zeeb 		sc->sdio_state = SDIO_STATE_READY;
1008*67ca7330SBjoern A. Zeeb 	else
1009*67ca7330SBjoern A. Zeeb 		sc->sdio_state = SDIO_STATE_DEAD;
1010*67ca7330SBjoern A. Zeeb 	cam_periph_unlock(periph);
1011*67ca7330SBjoern A. Zeeb 
1012*67ca7330SBjoern A. Zeeb 	if (error)
1013*67ca7330SBjoern A. Zeeb 		return;
1014*67ca7330SBjoern A. Zeeb 
1015*67ca7330SBjoern A. Zeeb 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s: num_func %d\n",
1016*67ca7330SBjoern A. Zeeb 	    __func__, sc->cardinfo.num_funcs));
1017*67ca7330SBjoern A. Zeeb 
1018*67ca7330SBjoern A. Zeeb 	/*
1019*67ca7330SBjoern A. Zeeb 	 * Now CAM portion of the driver has been initialized and
1020*67ca7330SBjoern A. Zeeb 	 * we know VID/PID of all the functions on the card.
1021*67ca7330SBjoern A. Zeeb 	 * Time to hook into the newbus.
1022*67ca7330SBjoern A. Zeeb 	 */
1023*67ca7330SBjoern A. Zeeb 	error = sdio_newbus_sim_add(sc);
1024*67ca7330SBjoern A. Zeeb 	if (error != 0)
1025*67ca7330SBjoern A. Zeeb 		sc->nb_state = NB_STATE_DEAD;
1026*67ca7330SBjoern A. Zeeb 
1027*67ca7330SBjoern A. Zeeb 	return;
1028*67ca7330SBjoern A. Zeeb }
1029*67ca7330SBjoern A. Zeeb 
1030*67ca7330SBjoern A. Zeeb /* Called at the end of cam_periph_alloc() for us to finish allocation. */
1031*67ca7330SBjoern A. Zeeb static cam_status
1032*67ca7330SBjoern A. Zeeb sdiobregister(struct cam_periph *periph, void *arg)
1033*67ca7330SBjoern A. Zeeb {
1034*67ca7330SBjoern A. Zeeb 	struct sdiob_softc *sc;
1035*67ca7330SBjoern A. Zeeb 	int error;
1036*67ca7330SBjoern A. Zeeb 
1037*67ca7330SBjoern A. Zeeb 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s: arg %p\n", __func__, arg));
1038*67ca7330SBjoern A. Zeeb 	if (arg == NULL) {
1039*67ca7330SBjoern A. Zeeb 		printf("%s: no getdev CCB, can't register device pariph %p\n",
1040*67ca7330SBjoern A. Zeeb 		    __func__, periph);
1041*67ca7330SBjoern A. Zeeb 		return(CAM_REQ_CMP_ERR);
1042*67ca7330SBjoern A. Zeeb 	}
1043*67ca7330SBjoern A. Zeeb 	if (periph->sim == NULL || periph->sim->sim_dev == NULL) {
1044*67ca7330SBjoern A. Zeeb 		printf("%s: no sim %p or sim_dev %p\n", __func__, periph->sim,
1045*67ca7330SBjoern A. Zeeb 		    (periph->sim != NULL) ? periph->sim->sim_dev : NULL);
1046*67ca7330SBjoern A. Zeeb 		return(CAM_REQ_CMP_ERR);
1047*67ca7330SBjoern A. Zeeb 	}
1048*67ca7330SBjoern A. Zeeb 
1049*67ca7330SBjoern A. Zeeb 	sc = (struct sdiob_softc *) malloc(sizeof(*sc), M_DEVBUF,
1050*67ca7330SBjoern A. Zeeb 	    M_NOWAIT|M_ZERO);
1051*67ca7330SBjoern A. Zeeb 	if (sc == NULL) {
1052*67ca7330SBjoern A. Zeeb 		printf("%s: unable to allocate sc\n", __func__);
1053*67ca7330SBjoern A. Zeeb 		return (CAM_REQ_CMP_ERR);
1054*67ca7330SBjoern A. Zeeb 	}
1055*67ca7330SBjoern A. Zeeb 	sc->sdio_state = SDIO_STATE_DEAD;
1056*67ca7330SBjoern A. Zeeb 	sc->nb_state = NB_STATE_DEAD;
1057*67ca7330SBjoern A. Zeeb 	TASK_INIT(&sc->discover_task, 0, sdiobdiscover, periph);
1058*67ca7330SBjoern A. Zeeb 
1059*67ca7330SBjoern A. Zeeb 	/* Refcount until we are setup.  Can't block. */
1060*67ca7330SBjoern A. Zeeb 	error = cam_periph_hold(periph, PRIBIO);
1061*67ca7330SBjoern A. Zeeb 	if (error != 0) {
1062*67ca7330SBjoern A. Zeeb 		printf("%s: lost periph during registration!\n", __func__);
1063*67ca7330SBjoern A. Zeeb 		free(sc, M_DEVBUF);
1064*67ca7330SBjoern A. Zeeb 		return(CAM_REQ_CMP_ERR);
1065*67ca7330SBjoern A. Zeeb 	}
1066*67ca7330SBjoern A. Zeeb 	periph->softc = sc;
1067*67ca7330SBjoern A. Zeeb 	sc->periph = periph;
1068*67ca7330SBjoern A. Zeeb 	cam_periph_unlock(periph);
1069*67ca7330SBjoern A. Zeeb 
1070*67ca7330SBjoern A. Zeeb 	error = taskqueue_enqueue(taskqueue_thread, &sc->discover_task);
1071*67ca7330SBjoern A. Zeeb 
1072*67ca7330SBjoern A. Zeeb 	cam_periph_lock(periph);
1073*67ca7330SBjoern A. Zeeb 	/* We will continue to hold a refcount for discover_task. */
1074*67ca7330SBjoern A. Zeeb 	/* cam_periph_unhold(periph); */
1075*67ca7330SBjoern A. Zeeb 
1076*67ca7330SBjoern A. Zeeb 	xpt_schedule(periph, CAM_PRIORITY_XPT);
1077*67ca7330SBjoern A. Zeeb 
1078*67ca7330SBjoern A. Zeeb 	return (CAM_REQ_CMP);
1079*67ca7330SBjoern A. Zeeb }
1080*67ca7330SBjoern A. Zeeb 
1081*67ca7330SBjoern A. Zeeb static void
1082*67ca7330SBjoern A. Zeeb sdioboninvalidate(struct cam_periph *periph)
1083*67ca7330SBjoern A. Zeeb {
1084*67ca7330SBjoern A. Zeeb 
1085*67ca7330SBjoern A. Zeeb 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s:\n", __func__));
1086*67ca7330SBjoern A. Zeeb 
1087*67ca7330SBjoern A. Zeeb 	return;
1088*67ca7330SBjoern A. Zeeb }
1089*67ca7330SBjoern A. Zeeb 
1090*67ca7330SBjoern A. Zeeb static void
1091*67ca7330SBjoern A. Zeeb sdiobcleanup(struct cam_periph *periph)
1092*67ca7330SBjoern A. Zeeb {
1093*67ca7330SBjoern A. Zeeb 
1094*67ca7330SBjoern A. Zeeb 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s:\n", __func__));
1095*67ca7330SBjoern A. Zeeb 
1096*67ca7330SBjoern A. Zeeb 	return;
1097*67ca7330SBjoern A. Zeeb }
1098*67ca7330SBjoern A. Zeeb 
1099*67ca7330SBjoern A. Zeeb static void
1100*67ca7330SBjoern A. Zeeb sdiobstart(struct cam_periph *periph, union ccb *ccb)
1101*67ca7330SBjoern A. Zeeb {
1102*67ca7330SBjoern A. Zeeb 
1103*67ca7330SBjoern A. Zeeb 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s: ccb %p\n", __func__, ccb));
1104*67ca7330SBjoern A. Zeeb 
1105*67ca7330SBjoern A. Zeeb 	return;
1106*67ca7330SBjoern A. Zeeb }
1107*67ca7330SBjoern A. Zeeb 
1108*67ca7330SBjoern A. Zeeb static void
1109*67ca7330SBjoern A. Zeeb sdiobasync(void *softc, uint32_t code, struct cam_path *path, void *arg)
1110*67ca7330SBjoern A. Zeeb {
1111*67ca7330SBjoern A. Zeeb 	struct cam_periph *periph;
1112*67ca7330SBjoern A. Zeeb 	struct ccb_getdev *cgd;
1113*67ca7330SBjoern A. Zeeb 	cam_status status;
1114*67ca7330SBjoern A. Zeeb 
1115*67ca7330SBjoern A. Zeeb 	periph = (struct cam_periph *)softc;
1116*67ca7330SBjoern A. Zeeb 
1117*67ca7330SBjoern A. Zeeb 	CAM_DEBUG(path, CAM_DEBUG_TRACE, ("%s(code=%d)\n", __func__, code));
1118*67ca7330SBjoern A. Zeeb 	switch (code) {
1119*67ca7330SBjoern A. Zeeb 	case AC_FOUND_DEVICE:
1120*67ca7330SBjoern A. Zeeb 		if (arg == NULL)
1121*67ca7330SBjoern A. Zeeb 			break;
1122*67ca7330SBjoern A. Zeeb 		cgd = (struct ccb_getdev *)arg;
1123*67ca7330SBjoern A. Zeeb 		if (cgd->protocol != PROTO_MMCSD)
1124*67ca7330SBjoern A. Zeeb 			break;
1125*67ca7330SBjoern A. Zeeb 
1126*67ca7330SBjoern A. Zeeb 		/* We do not support SD memory (Combo) Cards. */
1127*67ca7330SBjoern A. Zeeb 		if ((path->device->mmc_ident_data.card_features &
1128*67ca7330SBjoern A. Zeeb 		    CARD_FEATURE_MEMORY)) {
1129*67ca7330SBjoern A. Zeeb 			CAM_DEBUG(path, CAM_DEBUG_TRACE,
1130*67ca7330SBjoern A. Zeeb 			     ("Memory card, not interested\n"));
1131*67ca7330SBjoern A. Zeeb 			break;
1132*67ca7330SBjoern A. Zeeb 		}
1133*67ca7330SBjoern A. Zeeb 
1134*67ca7330SBjoern A. Zeeb 		/*
1135*67ca7330SBjoern A. Zeeb 		 * Allocate a peripheral instance for this device which starts
1136*67ca7330SBjoern A. Zeeb 		 * the probe process.
1137*67ca7330SBjoern A. Zeeb 		 */
1138*67ca7330SBjoern A. Zeeb 		status = cam_periph_alloc(sdiobregister, sdioboninvalidate,
1139*67ca7330SBjoern A. Zeeb 		    sdiobcleanup, sdiobstart, SDIOB_NAME_S, CAM_PERIPH_BIO, path,
1140*67ca7330SBjoern A. Zeeb 		    sdiobasync, AC_FOUND_DEVICE, cgd);
1141*67ca7330SBjoern A. Zeeb 		if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG)
1142*67ca7330SBjoern A. Zeeb 			CAM_DEBUG(path, CAM_DEBUG_PERIPH,
1143*67ca7330SBjoern A. Zeeb 			     ("%s: Unable to attach to new device due to "
1144*67ca7330SBjoern A. Zeeb 			     "status %#02x\n", __func__, status));
1145*67ca7330SBjoern A. Zeeb 		break;
1146*67ca7330SBjoern A. Zeeb 	default:
1147*67ca7330SBjoern A. Zeeb 		CAM_DEBUG(path, CAM_DEBUG_PERIPH,
1148*67ca7330SBjoern A. Zeeb 		     ("%s: cannot handle async code %#02x\n", __func__, code));
1149*67ca7330SBjoern A. Zeeb 		cam_periph_async(periph, code, path, arg);
1150*67ca7330SBjoern A. Zeeb 		break;
1151*67ca7330SBjoern A. Zeeb 	}
1152*67ca7330SBjoern A. Zeeb }
1153*67ca7330SBjoern A. Zeeb 
1154*67ca7330SBjoern A. Zeeb static void
1155*67ca7330SBjoern A. Zeeb sdiobinit(void)
1156*67ca7330SBjoern A. Zeeb {
1157*67ca7330SBjoern A. Zeeb 	cam_status status;
1158*67ca7330SBjoern A. Zeeb 
1159*67ca7330SBjoern A. Zeeb 	/*
1160*67ca7330SBjoern A. Zeeb 	 * Register for new device notification.  We will be notified for all
1161*67ca7330SBjoern A. Zeeb 	 * already existing ones.
1162*67ca7330SBjoern A. Zeeb 	 */
1163*67ca7330SBjoern A. Zeeb 	status = xpt_register_async(AC_FOUND_DEVICE, sdiobasync, NULL, NULL);
1164*67ca7330SBjoern A. Zeeb 	if (status != CAM_REQ_CMP)
1165*67ca7330SBjoern A. Zeeb 		printf("%s: Failed to attach async callback, statux %#02x",
1166*67ca7330SBjoern A. Zeeb 		    __func__, status);
1167*67ca7330SBjoern A. Zeeb }
1168*67ca7330SBjoern A. Zeeb 
1169*67ca7330SBjoern A. Zeeb /* This function will allow unloading the KLD. */
1170*67ca7330SBjoern A. Zeeb static int
1171*67ca7330SBjoern A. Zeeb sdiobdeinit(void)
1172*67ca7330SBjoern A. Zeeb {
1173*67ca7330SBjoern A. Zeeb 
1174*67ca7330SBjoern A. Zeeb 	return (EOPNOTSUPP);
1175*67ca7330SBjoern A. Zeeb }
1176*67ca7330SBjoern A. Zeeb 
1177*67ca7330SBjoern A. Zeeb static struct periph_driver sdiobdriver =
1178*67ca7330SBjoern A. Zeeb {
1179*67ca7330SBjoern A. Zeeb 	.init =		sdiobinit,
1180*67ca7330SBjoern A. Zeeb 	.driver_name =	SDIOB_NAME_S,
1181*67ca7330SBjoern A. Zeeb 	.units =	TAILQ_HEAD_INITIALIZER(sdiobdriver.units),
1182*67ca7330SBjoern A. Zeeb 	.generation =	0,
1183*67ca7330SBjoern A. Zeeb 	.flags =	0,
1184*67ca7330SBjoern A. Zeeb 	.deinit =	sdiobdeinit,
1185*67ca7330SBjoern A. Zeeb };
1186*67ca7330SBjoern A. Zeeb 
1187*67ca7330SBjoern A. Zeeb PERIPHDRIVER_DECLARE(SDIOB_NAME, sdiobdriver);
1188*67ca7330SBjoern A. Zeeb MODULE_VERSION(SDIOB_NAME, 1);
1189