diff options
author | imp <imp@FreeBSD.org> | 2007-05-15 05:49:14 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2007-05-15 05:49:14 +0000 |
commit | 9ebc525a3dfd64bc0787b41c97fd64fc6910aa29 (patch) | |
tree | d9f3f9eb16033766001af221c15f1da133aca654 /sys | |
parent | a5222a8523ddf169c50138e05e82be2d613bde4b (diff) | |
download | FreeBSD-src-9ebc525a3dfd64bc0787b41c97fd64fc6910aa29.zip FreeBSD-src-9ebc525a3dfd64bc0787b41c97fd64fc6910aa29.tar.gz |
First cut at making detach work. also add sdh as a possible mmc bridge.
Submitted by: Andrea Bittau
(Andrea may have updated patches, but I've tested these)
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/mmc/mmc.c | 33 | ||||
-rw-r--r-- | sys/dev/mmc/mmcsd.c | 42 |
2 files changed, 65 insertions, 10 deletions
diff --git a/sys/dev/mmc/mmc.c b/sys/dev/mmc/mmc.c index 83c13c3..ed452ee 100644 --- a/sys/dev/mmc/mmc.c +++ b/sys/dev/mmc/mmc.c @@ -117,7 +117,26 @@ mmc_attach(device_t dev) static int mmc_detach(device_t dev) { - return (EBUSY); /* XXX */ + struct mmc_softc *sc = device_get_softc(dev); + device_t *kids; + int i, nkid; + + /* kill children [ph33r]. -sorbo */ + if (device_get_children(sc->dev, &kids, &nkid) != 0) + return 0; + for (i = 0; i < nkid; i++) { + device_t kid = kids[i]; + void *ivar = device_get_ivars(kid); + + device_detach(kid); + device_delete_child(sc->dev, kid); + free(ivar, M_DEVBUF); + } + free(kids, M_TEMP); + + MMC_LOCK_DESTROY(sc); + + return 0; } static int @@ -553,6 +572,8 @@ mmc_discover_cards(struct mmc_softc *sc) while (1) { ivar = malloc(sizeof(struct mmc_ivars), M_DEVBUF, M_WAITOK); + if (!ivar) + return; err = mmc_all_send_cid(sc, ivar->raw_cid); if (err == MMC_ERR_TIMEOUT) break; @@ -568,13 +589,15 @@ mmc_discover_cards(struct mmc_softc *sc) // RO check mmc_send_csd(sc, ivar->rca, ivar->raw_csd); mmc_decode_csd(1, ivar->raw_csd, &ivar->csd); - printf("SD CARD: %lld bytes\n", ivar->csd.capacity); + printf("SD CARD: %lld bytes\n", (long long) + ivar->csd.capacity); child = device_add_child(sc->dev, NULL, -1); device_set_ivars(child, ivar); - break; + return; } panic("Write MMC card code here"); } + free(ivar, M_DEVBUF); } static void @@ -679,9 +702,6 @@ mmc_read_ivar(device_t bus, device_t child, int which, u_char *result) case MMC_IVAR_MEDIA_SIZE: *(int *)result = ivar->csd.capacity; break; - case MMC_IVAR_MODE: - *(int *)result = ivar->mode; - break; case MMC_IVAR_RCA: *(int *)result = ivar->rca; break; @@ -743,3 +763,4 @@ static devclass_t mmc_devclass; DRIVER_MODULE(mmc, at91_mci, mmc_driver, mmc_devclass, 0, 0); +DRIVER_MODULE(mmc, sdh, mmc_driver, mmc_devclass, 0, 0); diff --git a/sys/dev/mmc/mmcsd.c b/sys/dev/mmc/mmcsd.c index 314c8a0..5c317e2 100644 --- a/sys/dev/mmc/mmcsd.c +++ b/sys/dev/mmc/mmcsd.c @@ -50,6 +50,7 @@ struct mmcsd_softc { struct disk *disk; struct proc *p; struct bio_queue_head bio_queue; + int running; }; #define MULTI_BLOCK_READ_BROKEN @@ -104,6 +105,8 @@ mmcsd_attach(device_t dev) sc->disk->d_unit = device_get_unit(dev); disk_create(sc->disk, DISK_VERSION); bioq_init(&sc->bio_queue); + + sc->running = 1; kthread_create(&mmcsd_task, sc, &sc->p, 0, 0, "task: mmc/sd card"); return (0); @@ -112,7 +115,27 @@ mmcsd_attach(device_t dev) static int mmcsd_detach(device_t dev) { - return (EBUSY); /* XXX */ + struct mmcsd_softc *sc = device_get_softc(dev); + + /* kill thread */ + MMCSD_LOCK(sc); + sc->running = 0; + wakeup(sc); + MMCSD_UNLOCK(sc); + + /* wait for thread to finish. XXX probably want timeout. -sorbo */ + MMCSD_LOCK(sc); + while (sc->running != -1) + msleep(sc, &sc->sc_mtx, PRIBIO, "detach", 0); + MMCSD_UNLOCK(sc); + + /* kill disk */ + disk_destroy(sc->disk); + /* XXX destroy anything in queue */ + + MMCSD_LOCK_DESTROY(sc); + + return 0; } static int @@ -153,15 +176,18 @@ mmcsd_task(void *arg) device_t dev; dev = sc->dev; - for (;;) { + while (sc->running) { MMCSD_LOCK(sc); do { bp = bioq_first(&sc->bio_queue); if (bp == NULL) msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0); - } while (bp == NULL); - bioq_remove(&sc->bio_queue, bp); + } while (bp == NULL && sc->running); + if (bp) + bioq_remove(&sc->bio_queue, bp); MMCSD_UNLOCK(sc); + if (!sc->running) + break; MMCBUS_ACQUIRE_BUS(device_get_parent(dev), dev); // printf("mmc_task: request %p for block %lld\n", bp, bp->bio_pblkno); sz = sc->disk->d_sectorsize; @@ -224,6 +250,14 @@ mmcsd_task(void *arg) MMCBUS_RELEASE_BUS(device_get_parent(dev), dev); biodone(bp); } + + /* tell parent we're done */ + MMCSD_LOCK(sc); + sc->running = -1; + wakeup(sc); + MMCSD_UNLOCK(sc); + + kthread_exit(0); } static device_method_t mmcsd_methods[] = { |