mmcsd.c revision 169567
1163516Simp/*- 2163516Simp * Copyright (c) 2006 Bernd Walter. All rights reserved. 3163516Simp * Copyright (c) 2006 M. Warner Losh. All rights reserved. 4163516Simp * 5163516Simp * Redistribution and use in source and binary forms, with or without 6163516Simp * modification, are permitted provided that the following conditions 7163516Simp * are met: 8163516Simp * 1. Redistributions of source code must retain the above copyright 9163516Simp * notice, this list of conditions and the following disclaimer. 10163516Simp * 2. Redistributions in binary form must reproduce the above copyright 11163516Simp * notice, this list of conditions and the following disclaimer in the 12163516Simp * documentation and/or other materials provided with the distribution. 13163516Simp * 14163516Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15163516Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16163516Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17163516Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18163516Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19163516Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20163516Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21163516Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22163516Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23163516Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24163516Simp */ 25163516Simp 26163516Simp#include <sys/cdefs.h> 27163516Simp__FBSDID("$FreeBSD: head/sys/dev/mmc/mmcsd.c 169567 2007-05-15 05:49:14Z imp $"); 28163516Simp 29163516Simp#include <sys/param.h> 30163516Simp#include <sys/systm.h> 31163516Simp#include <sys/bio.h> 32163516Simp#include <sys/bus.h> 33163516Simp#include <sys/conf.h> 34163516Simp#include <sys/kernel.h> 35163516Simp#include <sys/kthread.h> 36163516Simp#include <sys/lock.h> 37163516Simp#include <sys/malloc.h> 38163516Simp#include <sys/module.h> 39163516Simp#include <sys/mutex.h> 40163516Simp#include <geom/geom_disk.h> 41163516Simp 42163516Simp#include <dev/mmc/mmcvar.h> 43163516Simp#include <dev/mmc/mmcreg.h> 44163516Simp 45163516Simp#include "mmcbus_if.h" 46163516Simp 47163516Simpstruct mmcsd_softc { 48163516Simp device_t dev; 49163516Simp struct mtx sc_mtx; 50163516Simp struct disk *disk; 51163516Simp struct proc *p; 52163516Simp struct bio_queue_head bio_queue; 53169567Simp int running; 54163516Simp}; 55163516Simp 56163516Simp#define MULTI_BLOCK_READ_BROKEN 57163516Simp 58163516Simp/* bus entry points */ 59163516Simpstatic int mmcsd_probe(device_t dev); 60163516Simpstatic int mmcsd_attach(device_t dev); 61163516Simpstatic int mmcsd_detach(device_t dev); 62163516Simp 63163516Simp/* disk routines */ 64163516Simpstatic int mmcsd_open(struct disk *dp); 65163516Simpstatic int mmcsd_close(struct disk *dp); 66163516Simpstatic void mmcsd_strategy(struct bio *bp); 67163516Simpstatic void mmcsd_task(void *arg); 68163516Simp 69163516Simp#define MMCSD_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 70163516Simp#define MMCSD_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 71163516Simp#define MMCSD_LOCK_INIT(_sc) \ 72163516Simp mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ 73163516Simp "mmcsd", MTX_DEF) 74163516Simp#define MMCSD_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 75163516Simp#define MMCSD_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); 76163516Simp#define MMCSD_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); 77163516Simp 78163516Simpstatic int 79163516Simpmmcsd_probe(device_t dev) 80163516Simp{ 81163516Simp 82163516Simp device_set_desc(dev, "mmc or sd flash card"); 83163516Simp return (0); 84163516Simp} 85163516Simp 86163516Simpstatic int 87163516Simpmmcsd_attach(device_t dev) 88163516Simp{ 89163516Simp struct mmcsd_softc *sc; 90163516Simp 91163516Simp sc = device_get_softc(dev); 92163516Simp sc->dev = dev; 93163516Simp MMCSD_LOCK_INIT(sc); 94163516Simp 95163516Simp sc->disk = disk_alloc(); 96163516Simp sc->disk->d_open = mmcsd_open; 97163516Simp sc->disk->d_close = mmcsd_close; 98163516Simp sc->disk->d_strategy = mmcsd_strategy; 99163516Simp // sc->disk->d_dump = mmcsd_dump; Need polling mmc layer 100163516Simp sc->disk->d_name = "mmcsd"; 101163516Simp sc->disk->d_drv1 = sc; 102163516Simp sc->disk->d_maxsize = DFLTPHYS; 103163516Simp sc->disk->d_sectorsize = mmc_get_sector_size(dev); 104163516Simp sc->disk->d_mediasize = mmc_get_media_size(dev); 105163516Simp sc->disk->d_unit = device_get_unit(dev); 106163516Simp disk_create(sc->disk, DISK_VERSION); 107163516Simp bioq_init(&sc->bio_queue); 108169567Simp 109169567Simp sc->running = 1; 110163516Simp kthread_create(&mmcsd_task, sc, &sc->p, 0, 0, "task: mmc/sd card"); 111163516Simp 112163516Simp return (0); 113163516Simp} 114163516Simp 115163516Simpstatic int 116163516Simpmmcsd_detach(device_t dev) 117163516Simp{ 118169567Simp struct mmcsd_softc *sc = device_get_softc(dev); 119169567Simp 120169567Simp /* kill thread */ 121169567Simp MMCSD_LOCK(sc); 122169567Simp sc->running = 0; 123169567Simp wakeup(sc); 124169567Simp MMCSD_UNLOCK(sc); 125169567Simp 126169567Simp /* wait for thread to finish. XXX probably want timeout. -sorbo */ 127169567Simp MMCSD_LOCK(sc); 128169567Simp while (sc->running != -1) 129169567Simp msleep(sc, &sc->sc_mtx, PRIBIO, "detach", 0); 130169567Simp MMCSD_UNLOCK(sc); 131169567Simp 132169567Simp /* kill disk */ 133169567Simp disk_destroy(sc->disk); 134169567Simp /* XXX destroy anything in queue */ 135169567Simp 136169567Simp MMCSD_LOCK_DESTROY(sc); 137169567Simp 138169567Simp return 0; 139163516Simp} 140163516Simp 141163516Simpstatic int 142163516Simpmmcsd_open(struct disk *dp) 143163516Simp{ 144163516Simp return 0; 145163516Simp} 146163516Simp 147163516Simpstatic int 148163516Simpmmcsd_close(struct disk *dp) 149163516Simp{ 150163516Simp return 0; 151163516Simp} 152163516Simp 153163516Simpstatic void 154163516Simpmmcsd_strategy(struct bio *bp) 155163516Simp{ 156163516Simp struct mmcsd_softc *sc; 157163516Simp 158163516Simp sc = (struct mmcsd_softc *)bp->bio_disk->d_drv1; 159163516Simp MMCSD_LOCK(sc); 160163516Simp bioq_disksort(&sc->bio_queue, bp); 161163516Simp wakeup(sc); 162163516Simp MMCSD_UNLOCK(sc); 163163516Simp} 164163516Simp 165163516Simpstatic void 166163516Simpmmcsd_task(void *arg) 167163516Simp{ 168163516Simp struct mmcsd_softc *sc = (struct mmcsd_softc*)arg; 169163516Simp struct bio *bp; 170163516Simp int sz; 171163516Simp daddr_t block, end; 172163516Simp struct mmc_command cmd; 173163516Simp struct mmc_command stop; 174163516Simp struct mmc_request req; 175163516Simp struct mmc_data data; 176163516Simp device_t dev; 177163516Simp 178163516Simp dev = sc->dev; 179169567Simp while (sc->running) { 180163516Simp MMCSD_LOCK(sc); 181163516Simp do { 182163516Simp bp = bioq_first(&sc->bio_queue); 183163516Simp if (bp == NULL) 184163516Simp msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0); 185169567Simp } while (bp == NULL && sc->running); 186169567Simp if (bp) 187169567Simp bioq_remove(&sc->bio_queue, bp); 188163516Simp MMCSD_UNLOCK(sc); 189169567Simp if (!sc->running) 190169567Simp break; 191163516Simp MMCBUS_ACQUIRE_BUS(device_get_parent(dev), dev); 192163516Simp// printf("mmc_task: request %p for block %lld\n", bp, bp->bio_pblkno); 193163516Simp sz = sc->disk->d_sectorsize; 194163516Simp end = bp->bio_pblkno + (bp->bio_bcount / sz); 195163516Simp // XXX should use read/write_mulit 196163516Simp for (block = bp->bio_pblkno; block < end;) { 197163516Simp char *vaddr = bp->bio_data + (block - bp->bio_pblkno) * sz; 198163516Simp memset(&req, 0, sizeof(req)); 199163516Simp memset(&cmd, 0, sizeof(cmd)); 200163516Simp memset(&stop, 0, sizeof(stop)); 201163516Simp req.cmd = &cmd; 202163516Simp cmd.data = &data; 203163516Simp if (bp->bio_cmd == BIO_READ) { 204163516Simp#ifdef MULTI_BLOCK_READ 205163516Simp if (end - block > 1) 206163516Simp cmd.opcode = MMC_READ_MULTIPLE_BLOCK; 207163516Simp else 208163516Simp cmd.opcode = MMC_READ_SINGLE_BLOCK; 209163516Simp#else 210163516Simp cmd.opcode = MMC_READ_SINGLE_BLOCK; 211163516Simp#endif 212163516Simp } else 213163516Simp cmd.opcode = MMC_WRITE_BLOCK; 214163516Simp cmd.arg = block << 9; 215163516Simp cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; 216163516Simp // data.timeout_ns = ; 217163516Simp // data.timeout_clks = ; 218163516Simp data.data = vaddr; 219163516Simp data.mrq = &req; 220163516Simp if (bp->bio_cmd == BIO_READ) { 221163516Simp data.flags = MMC_DATA_READ; 222163516Simp#ifdef MULTI_BLOCK_READ 223163516Simp data.len = bp->bio_bcount; 224163516Simp if (end - block > 1) { 225163516Simp req.stop = &stop; 226163516Simp data.flags |= MMC_DATA_MULTI; 227163516Simp } 228163516Simp printf("Len %d %lld-%lld flags %#x sz %d\n", 229163516Simp data.len, block, end, data.flags, sz); 230163516Simp block = end; 231163516Simp#else 232163516Simp data.len = sz; 233163516Simp block++; 234163516Simp#endif 235163516Simp } else { 236163516Simp data.flags = MMC_DATA_WRITE; 237163516Simp data.len = sz; 238163516Simp block++; 239163516Simp } 240163516Simp stop.opcode = MMC_STOP_TRANSMISSION; 241163516Simp stop.arg = 0; 242163516Simp stop.flags = MMC_RSP_R1B | MMC_CMD_AC; 243163516Simp MMCBUS_WAIT_FOR_REQUEST(device_get_parent(dev), dev, 244163516Simp &req); 245163516Simp // XXX error handling 246163516Simp//XXX while (!(mmc_send_status(dev) & R1_READY_FOR_DATA)) 247163516Simp// continue; 248163516Simp // XXX decode mmc status 249163516Simp } 250163516Simp MMCBUS_RELEASE_BUS(device_get_parent(dev), dev); 251163516Simp biodone(bp); 252163516Simp } 253169567Simp 254169567Simp /* tell parent we're done */ 255169567Simp MMCSD_LOCK(sc); 256169567Simp sc->running = -1; 257169567Simp wakeup(sc); 258169567Simp MMCSD_UNLOCK(sc); 259169567Simp 260169567Simp kthread_exit(0); 261163516Simp} 262163516Simp 263163516Simpstatic device_method_t mmcsd_methods[] = { 264163516Simp DEVMETHOD(device_probe, mmcsd_probe), 265163516Simp DEVMETHOD(device_attach, mmcsd_attach), 266163516Simp DEVMETHOD(device_detach, mmcsd_detach), 267163516Simp {0, 0}, 268163516Simp}; 269163516Simp 270163516Simpstatic driver_t mmcsd_driver = { 271163516Simp "mmcsd", 272163516Simp mmcsd_methods, 273163516Simp sizeof(struct mmcsd_softc), 274163516Simp}; 275163516Simpstatic devclass_t mmcsd_devclass; 276163516Simp 277163516Simp 278163516SimpDRIVER_MODULE(mmcsd, mmc, mmcsd_driver, mmcsd_devclass, 0, 0); 279