Deleted Added
full compact
mmcsd.c (183542) mmcsd.c (183704)
1/*-
2 * Copyright (c) 2006 Bernd Walter. All rights reserved.
3 * Copyright (c) 2006 M. Warner Losh. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 * Portions of this software may have been developed with reference to
26 * the SD Simplified Specification. The following disclaimer may apply:
27 *
28 * The following conditions apply to the release of the simplified
29 * specification ("Simplified Specification") by the SD Card Association and
30 * the SD Group. The Simplified Specification is a subset of the complete SD
31 * Specification which is owned by the SD Card Association and the SD
32 * Group. This Simplified Specification is provided on a non-confidential
33 * basis subject to the disclaimers below. Any implementation of the
34 * Simplified Specification may require a license from the SD Card
35 * Association, SD Group, SD-3C LLC or other third parties.
36 *
37 * Disclaimers:
38 *
39 * The information contained in the Simplified Specification is presented only
40 * as a standard specification for SD Cards and SD Host/Ancillary products and
41 * is provided "AS-IS" without any representations or warranties of any
42 * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
43 * Card Association for any damages, any infringements of patents or other
44 * right of the SD Group, SD-3C LLC, the SD Card Association or any third
45 * parties, which may result from its use. No license is granted by
46 * implication, estoppel or otherwise under any patent or other rights of the
47 * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
48 * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
49 * or the SD Card Association to disclose or distribute any technical
50 * information, know-how or other confidential information to any third party.
51 */
52
53#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2006 Bernd Walter. All rights reserved.
3 * Copyright (c) 2006 M. Warner Losh. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 * Portions of this software may have been developed with reference to
26 * the SD Simplified Specification. The following disclaimer may apply:
27 *
28 * The following conditions apply to the release of the simplified
29 * specification ("Simplified Specification") by the SD Card Association and
30 * the SD Group. The Simplified Specification is a subset of the complete SD
31 * Specification which is owned by the SD Card Association and the SD
32 * Group. This Simplified Specification is provided on a non-confidential
33 * basis subject to the disclaimers below. Any implementation of the
34 * Simplified Specification may require a license from the SD Card
35 * Association, SD Group, SD-3C LLC or other third parties.
36 *
37 * Disclaimers:
38 *
39 * The information contained in the Simplified Specification is presented only
40 * as a standard specification for SD Cards and SD Host/Ancillary products and
41 * is provided "AS-IS" without any representations or warranties of any
42 * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
43 * Card Association for any damages, any infringements of patents or other
44 * right of the SD Group, SD-3C LLC, the SD Card Association or any third
45 * parties, which may result from its use. No license is granted by
46 * implication, estoppel or otherwise under any patent or other rights of the
47 * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
48 * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
49 * or the SD Card Association to disclose or distribute any technical
50 * information, know-how or other confidential information to any third party.
51 */
52
53#include <sys/cdefs.h>
54__FBSDID("$FreeBSD: head/sys/dev/mmc/mmcsd.c 183542 2008-10-02 07:06:59Z imp $");
54__FBSDID("$FreeBSD: head/sys/dev/mmc/mmcsd.c 183704 2008-10-08 17:35:41Z mav $");
55
56#include <sys/param.h>
57#include <sys/systm.h>
58#include <sys/bio.h>
59#include <sys/bus.h>
60#include <sys/conf.h>
61#include <sys/kernel.h>
62#include <sys/kthread.h>
63#include <sys/lock.h>
64#include <sys/malloc.h>
65#include <sys/module.h>
66#include <sys/mutex.h>
67#include <geom/geom_disk.h>
68
69#include <dev/mmc/mmcvar.h>
70#include <dev/mmc/mmcreg.h>
71
72#include "mmcbus_if.h"
73
74struct mmcsd_softc {
75 device_t dev;
76 struct mtx sc_mtx;
77 struct disk *disk;
78 struct proc *p;
79 struct bio_queue_head bio_queue;
80 int running;
81};
82
83#define MULTI_BLOCK_BROKEN
84
85/* bus entry points */
86static int mmcsd_probe(device_t dev);
87static int mmcsd_attach(device_t dev);
88static int mmcsd_detach(device_t dev);
89
90/* disk routines */
91static int mmcsd_open(struct disk *dp);
92static int mmcsd_close(struct disk *dp);
93static void mmcsd_strategy(struct bio *bp);
94static void mmcsd_task(void *arg);
95
96#define MMCSD_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
97#define MMCSD_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
98#define MMCSD_LOCK_INIT(_sc) \
99 mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
100 "mmcsd", MTX_DEF)
101#define MMCSD_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
102#define MMCSD_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
103#define MMCSD_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
104
105static int
106mmcsd_probe(device_t dev)
107{
108
55
56#include <sys/param.h>
57#include <sys/systm.h>
58#include <sys/bio.h>
59#include <sys/bus.h>
60#include <sys/conf.h>
61#include <sys/kernel.h>
62#include <sys/kthread.h>
63#include <sys/lock.h>
64#include <sys/malloc.h>
65#include <sys/module.h>
66#include <sys/mutex.h>
67#include <geom/geom_disk.h>
68
69#include <dev/mmc/mmcvar.h>
70#include <dev/mmc/mmcreg.h>
71
72#include "mmcbus_if.h"
73
74struct mmcsd_softc {
75 device_t dev;
76 struct mtx sc_mtx;
77 struct disk *disk;
78 struct proc *p;
79 struct bio_queue_head bio_queue;
80 int running;
81};
82
83#define MULTI_BLOCK_BROKEN
84
85/* bus entry points */
86static int mmcsd_probe(device_t dev);
87static int mmcsd_attach(device_t dev);
88static int mmcsd_detach(device_t dev);
89
90/* disk routines */
91static int mmcsd_open(struct disk *dp);
92static int mmcsd_close(struct disk *dp);
93static void mmcsd_strategy(struct bio *bp);
94static void mmcsd_task(void *arg);
95
96#define MMCSD_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
97#define MMCSD_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
98#define MMCSD_LOCK_INIT(_sc) \
99 mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
100 "mmcsd", MTX_DEF)
101#define MMCSD_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
102#define MMCSD_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
103#define MMCSD_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
104
105static int
106mmcsd_probe(device_t dev)
107{
108
109 device_quiet(dev);
109 device_set_desc(dev, "MMC/SD Memory Card");
110 return (0);
111}
112
113static int
114mmcsd_attach(device_t dev)
115{
116 struct mmcsd_softc *sc;
117
118 sc = device_get_softc(dev);
119 sc->dev = dev;
120 MMCSD_LOCK_INIT(sc);
121
122 sc->disk = disk_alloc();
123 sc->disk->d_open = mmcsd_open;
124 sc->disk->d_close = mmcsd_close;
125 sc->disk->d_strategy = mmcsd_strategy;
126 // sc->disk->d_dump = mmcsd_dump; Need polling mmc layer
127 sc->disk->d_name = "mmcsd";
128 sc->disk->d_drv1 = sc;
129 sc->disk->d_maxsize = MAXPHYS; /* Maybe ask bridge? */
130 sc->disk->d_sectorsize = mmc_get_sector_size(dev);
131 sc->disk->d_mediasize = mmc_get_media_size(dev) *
132 mmc_get_sector_size(dev);
133 sc->disk->d_unit = device_get_unit(dev);
134
135 device_printf(dev, "%juMB <MMC/SD Memory Card>%s at %s\n",
136 sc->disk->d_mediasize / 1048576,
137 mmc_get_read_only(dev)?" (read-only)":"",
138 device_get_nameunit(device_get_parent(sc->dev)));
139 disk_create(sc->disk, DISK_VERSION);
140 bioq_init(&sc->bio_queue);
141
142 sc->running = 1;
143 kproc_create(&mmcsd_task, sc, &sc->p, 0, 0, "task: mmc/sd card");
144
145 return (0);
146}
147
148static int
149mmcsd_detach(device_t dev)
150{
151 struct mmcsd_softc *sc = device_get_softc(dev);
152
153 /* kill thread */
154 MMCSD_LOCK(sc);
155 sc->running = 0;
156 wakeup(sc);
157 MMCSD_UNLOCK(sc);
158
159 /* wait for thread to finish. XXX probably want timeout. -sorbo */
160 MMCSD_LOCK(sc);
161 while (sc->running != -1)
162 msleep(sc, &sc->sc_mtx, PRIBIO, "detach", 0);
163 MMCSD_UNLOCK(sc);
164
165 /* kill disk */
166 disk_destroy(sc->disk);
167 /* XXX destroy anything in queue */
168
169 MMCSD_LOCK_DESTROY(sc);
170
171 return (0);
172}
173
174static int
175mmcsd_open(struct disk *dp)
176{
177 return (0);
178}
179
180static int
181mmcsd_close(struct disk *dp)
182{
183 return (0);
184}
185
186static void
187mmcsd_strategy(struct bio *bp)
188{
189 struct mmcsd_softc *sc;
190
191 sc = (struct mmcsd_softc *)bp->bio_disk->d_drv1;
192 MMCSD_LOCK(sc);
193 bioq_disksort(&sc->bio_queue, bp);
194 wakeup(sc);
195 MMCSD_UNLOCK(sc);
196}
197
198static void
199mmcsd_task(void *arg)
200{
201 struct mmcsd_softc *sc = (struct mmcsd_softc*)arg;
202 struct bio *bp;
203 int sz;
204 daddr_t block, end;
205 struct mmc_command cmd;
206 struct mmc_command stop;
207 struct mmc_request req;
208 struct mmc_data data;
209 device_t dev;
210
211 dev = sc->dev;
212 while (sc->running) {
213 MMCSD_LOCK(sc);
214 do {
215 bp = bioq_first(&sc->bio_queue);
216 if (bp == NULL)
217 msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0);
218 } while (bp == NULL && sc->running);
219 if (bp)
220 bioq_remove(&sc->bio_queue, bp);
221 MMCSD_UNLOCK(sc);
222 if (!sc->running)
223 break;
224// printf("mmc_task: request %p for block %ju\n", bp, bp->bio_pblkno);
225 if (bp->bio_cmd != BIO_READ && mmc_get_read_only(dev)) {
226 bp->bio_error = EROFS;
227 bp->bio_resid = bp->bio_bcount;
228 bp->bio_flags |= BIO_ERROR;
229 biodone(bp);
230 continue;
231 }
232 MMCBUS_ACQUIRE_BUS(device_get_parent(dev), dev);
233 sz = sc->disk->d_sectorsize;
234 end = bp->bio_pblkno + (bp->bio_bcount / sz);
235 for (block = bp->bio_pblkno; block < end;) {
236 char *vaddr = bp->bio_data + (block - bp->bio_pblkno) * sz;
237 int numblocks;
238#ifdef MULTI_BLOCK
239 numblocks = end - block;
240#else
241 numblocks = 1;
242#endif
243 memset(&req, 0, sizeof(req));
244 memset(&cmd, 0, sizeof(cmd));
245 memset(&stop, 0, sizeof(stop));
246 req.cmd = &cmd;
247 cmd.data = &data;
248 if (bp->bio_cmd == BIO_READ) {
249 if (numblocks > 1)
250 cmd.opcode = MMC_READ_MULTIPLE_BLOCK;
251 else
252 cmd.opcode = MMC_READ_SINGLE_BLOCK;
253 } else {
254 if (numblocks > 1)
255 cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK;
256 else
257 cmd.opcode = MMC_WRITE_BLOCK;
258 }
110 device_set_desc(dev, "MMC/SD Memory Card");
111 return (0);
112}
113
114static int
115mmcsd_attach(device_t dev)
116{
117 struct mmcsd_softc *sc;
118
119 sc = device_get_softc(dev);
120 sc->dev = dev;
121 MMCSD_LOCK_INIT(sc);
122
123 sc->disk = disk_alloc();
124 sc->disk->d_open = mmcsd_open;
125 sc->disk->d_close = mmcsd_close;
126 sc->disk->d_strategy = mmcsd_strategy;
127 // sc->disk->d_dump = mmcsd_dump; Need polling mmc layer
128 sc->disk->d_name = "mmcsd";
129 sc->disk->d_drv1 = sc;
130 sc->disk->d_maxsize = MAXPHYS; /* Maybe ask bridge? */
131 sc->disk->d_sectorsize = mmc_get_sector_size(dev);
132 sc->disk->d_mediasize = mmc_get_media_size(dev) *
133 mmc_get_sector_size(dev);
134 sc->disk->d_unit = device_get_unit(dev);
135
136 device_printf(dev, "%juMB <MMC/SD Memory Card>%s at %s\n",
137 sc->disk->d_mediasize / 1048576,
138 mmc_get_read_only(dev)?" (read-only)":"",
139 device_get_nameunit(device_get_parent(sc->dev)));
140 disk_create(sc->disk, DISK_VERSION);
141 bioq_init(&sc->bio_queue);
142
143 sc->running = 1;
144 kproc_create(&mmcsd_task, sc, &sc->p, 0, 0, "task: mmc/sd card");
145
146 return (0);
147}
148
149static int
150mmcsd_detach(device_t dev)
151{
152 struct mmcsd_softc *sc = device_get_softc(dev);
153
154 /* kill thread */
155 MMCSD_LOCK(sc);
156 sc->running = 0;
157 wakeup(sc);
158 MMCSD_UNLOCK(sc);
159
160 /* wait for thread to finish. XXX probably want timeout. -sorbo */
161 MMCSD_LOCK(sc);
162 while (sc->running != -1)
163 msleep(sc, &sc->sc_mtx, PRIBIO, "detach", 0);
164 MMCSD_UNLOCK(sc);
165
166 /* kill disk */
167 disk_destroy(sc->disk);
168 /* XXX destroy anything in queue */
169
170 MMCSD_LOCK_DESTROY(sc);
171
172 return (0);
173}
174
175static int
176mmcsd_open(struct disk *dp)
177{
178 return (0);
179}
180
181static int
182mmcsd_close(struct disk *dp)
183{
184 return (0);
185}
186
187static void
188mmcsd_strategy(struct bio *bp)
189{
190 struct mmcsd_softc *sc;
191
192 sc = (struct mmcsd_softc *)bp->bio_disk->d_drv1;
193 MMCSD_LOCK(sc);
194 bioq_disksort(&sc->bio_queue, bp);
195 wakeup(sc);
196 MMCSD_UNLOCK(sc);
197}
198
199static void
200mmcsd_task(void *arg)
201{
202 struct mmcsd_softc *sc = (struct mmcsd_softc*)arg;
203 struct bio *bp;
204 int sz;
205 daddr_t block, end;
206 struct mmc_command cmd;
207 struct mmc_command stop;
208 struct mmc_request req;
209 struct mmc_data data;
210 device_t dev;
211
212 dev = sc->dev;
213 while (sc->running) {
214 MMCSD_LOCK(sc);
215 do {
216 bp = bioq_first(&sc->bio_queue);
217 if (bp == NULL)
218 msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0);
219 } while (bp == NULL && sc->running);
220 if (bp)
221 bioq_remove(&sc->bio_queue, bp);
222 MMCSD_UNLOCK(sc);
223 if (!sc->running)
224 break;
225// printf("mmc_task: request %p for block %ju\n", bp, bp->bio_pblkno);
226 if (bp->bio_cmd != BIO_READ && mmc_get_read_only(dev)) {
227 bp->bio_error = EROFS;
228 bp->bio_resid = bp->bio_bcount;
229 bp->bio_flags |= BIO_ERROR;
230 biodone(bp);
231 continue;
232 }
233 MMCBUS_ACQUIRE_BUS(device_get_parent(dev), dev);
234 sz = sc->disk->d_sectorsize;
235 end = bp->bio_pblkno + (bp->bio_bcount / sz);
236 for (block = bp->bio_pblkno; block < end;) {
237 char *vaddr = bp->bio_data + (block - bp->bio_pblkno) * sz;
238 int numblocks;
239#ifdef MULTI_BLOCK
240 numblocks = end - block;
241#else
242 numblocks = 1;
243#endif
244 memset(&req, 0, sizeof(req));
245 memset(&cmd, 0, sizeof(cmd));
246 memset(&stop, 0, sizeof(stop));
247 req.cmd = &cmd;
248 cmd.data = &data;
249 if (bp->bio_cmd == BIO_READ) {
250 if (numblocks > 1)
251 cmd.opcode = MMC_READ_MULTIPLE_BLOCK;
252 else
253 cmd.opcode = MMC_READ_SINGLE_BLOCK;
254 } else {
255 if (numblocks > 1)
256 cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK;
257 else
258 cmd.opcode = MMC_WRITE_BLOCK;
259 }
259 cmd.arg = block << 9;
260 cmd.arg = block;
261 if (!mmc_get_high_cap(dev))
262 cmd.arg <<= 9;
260 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
261 data.data = vaddr;
262 data.mrq = &req;
263 if (bp->bio_cmd == BIO_READ)
264 data.flags = MMC_DATA_READ;
265 else
266 data.flags = MMC_DATA_WRITE;
267 data.len = numblocks * sz;
268 if (numblocks > 1) {
269 data.flags |= MMC_DATA_MULTI;
270 stop.opcode = MMC_STOP_TRANSMISSION;
271 stop.arg = 0;
272 stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
273 req.stop = &stop;
274 }
275// printf("Len %d %lld-%lld flags %#x sz %d\n",
276// (int)data.len, (long long)block, (long long)end, data.flags, sz);
277 MMCBUS_WAIT_FOR_REQUEST(device_get_parent(dev), dev,
278 &req);
279 if (req.cmd->error != MMC_ERR_NONE)
280 break;
281 block += numblocks;
282 }
283 MMCBUS_RELEASE_BUS(device_get_parent(dev), dev);
284 if (block < end) {
285 bp->bio_error = EIO;
286 bp->bio_resid = (end - block) * sz;
287 bp->bio_flags |= BIO_ERROR;
288 }
289 biodone(bp);
290 }
291
292 /* tell parent we're done */
293 MMCSD_LOCK(sc);
294 sc->running = -1;
295 wakeup(sc);
296 MMCSD_UNLOCK(sc);
297
298 kproc_exit(0);
299}
300
301static device_method_t mmcsd_methods[] = {
302 DEVMETHOD(device_probe, mmcsd_probe),
303 DEVMETHOD(device_attach, mmcsd_attach),
304 DEVMETHOD(device_detach, mmcsd_detach),
305 {0, 0},
306};
307
308static driver_t mmcsd_driver = {
309 "mmcsd",
310 mmcsd_methods,
311 sizeof(struct mmcsd_softc),
312};
313static devclass_t mmcsd_devclass;
314
315
316DRIVER_MODULE(mmcsd, mmc, mmcsd_driver, mmcsd_devclass, 0, 0);
263 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
264 data.data = vaddr;
265 data.mrq = &req;
266 if (bp->bio_cmd == BIO_READ)
267 data.flags = MMC_DATA_READ;
268 else
269 data.flags = MMC_DATA_WRITE;
270 data.len = numblocks * sz;
271 if (numblocks > 1) {
272 data.flags |= MMC_DATA_MULTI;
273 stop.opcode = MMC_STOP_TRANSMISSION;
274 stop.arg = 0;
275 stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
276 req.stop = &stop;
277 }
278// printf("Len %d %lld-%lld flags %#x sz %d\n",
279// (int)data.len, (long long)block, (long long)end, data.flags, sz);
280 MMCBUS_WAIT_FOR_REQUEST(device_get_parent(dev), dev,
281 &req);
282 if (req.cmd->error != MMC_ERR_NONE)
283 break;
284 block += numblocks;
285 }
286 MMCBUS_RELEASE_BUS(device_get_parent(dev), dev);
287 if (block < end) {
288 bp->bio_error = EIO;
289 bp->bio_resid = (end - block) * sz;
290 bp->bio_flags |= BIO_ERROR;
291 }
292 biodone(bp);
293 }
294
295 /* tell parent we're done */
296 MMCSD_LOCK(sc);
297 sc->running = -1;
298 wakeup(sc);
299 MMCSD_UNLOCK(sc);
300
301 kproc_exit(0);
302}
303
304static device_method_t mmcsd_methods[] = {
305 DEVMETHOD(device_probe, mmcsd_probe),
306 DEVMETHOD(device_attach, mmcsd_attach),
307 DEVMETHOD(device_detach, mmcsd_detach),
308 {0, 0},
309};
310
311static driver_t mmcsd_driver = {
312 "mmcsd",
313 mmcsd_methods,
314 sizeof(struct mmcsd_softc),
315};
316static devclass_t mmcsd_devclass;
317
318
319DRIVER_MODULE(mmcsd, mmc, mmcsd_driver, mmcsd_devclass, 0, 0);