- Main Page
- Related Pages
- Data Structures
- Files

- File List
- Globals

# drivers/block/sdmmc.c

Go to the documentation of this file.

    00001
    00043 #include <assert.h>
    00044 #include <bitops.h>
    00045 #include <debug.h>
    00046 #include <malloc.h>
    00047 #include <status-codes.h>
    00048 #include <string.h>
    00049 #include <workqueue.h>
    00050 #include <sdmmc/sdmmc.h>
    00051 #include <block/device.h>
    00052 #include <block/sdmmc.h>
    00053
    00054 struct sdmmc_bdev {
    00055         struct block_device     bdev;
    00056         struct sdmmc_slot       *slot;
    00057         void                    (*event)(struct block_device *blkdev,
    00058                         void *context);
    00059         void                    *context;
    00060 };
    00061
    00062 struct sdmmc_breq {
    00063         struct block_request    block_req;
    00064         struct sdmmc_request    sdmmc_req;
    00065 };
    00066
    00067 static inline struct sdmmc_breq *sdmmc_breq_of(struct block_request *req)
    00068 {
    00069         return container_of(req, struct sdmmc_breq, block_req);
    00070 }
    00071
    00072 static inline struct sdmmc_slot *sdmmc_slot_of(struct block_device *bdev)
    00073 {
    00074         struct sdmmc_bdev *sbdev = container_of(bdev, struct sdmmc_bdev, bdev);
    00075         return sbdev->slot;
    00076 }
    00077
    00078 static void sdmmc_blkdev_submit_req(struct block_device *bdev,
    00079                 struct block_request *req)
    00080 {
    00081         struct sdmmc_slot       *slot = sdmmc_slot_of(bdev);
    00082         struct sdmmc_breq       *breq = sdmmc_breq_of(req);
    00083
    00084         if (!slist_is_empty(&breq->block_req.buf_list))
    00085                 slist_move_to_tail(&breq->sdmmc_req.buf_list,
    00086                                 &breq->block_req.buf_list);
    00087         sdmmc_slot_submit_req(slot, &breq->sdmmc_req);
    00088 }
    00089
    00090 static int sdmmc_blkdev_submit_buf_list(struct block_device *bdev,
    00091                 struct block_request *req, struct slist *buf_list)
    00092 {
    00093         struct sdmmc_slot       *slot = sdmmc_slot_of(bdev);
    00094         struct sdmmc_breq       *breq = sdmmc_breq_of(req);
    00095
    00096         return sdmmc_req_submit_buf_list(slot->host,
    00097                         &breq->sdmmc_req, buf_list);
    00098 }
    00099
    00100 static void sdmmc_blkdev_req_started(struct sdmmc_request *req)
    00101 {
    00102         struct sdmmc_breq       *breq = req->context;
    00103
    00104         if (breq->block_req.req_started)
    00105                 breq->block_req.req_started(breq->block_req.bdev,
    00106                                 &breq->block_req);
    00107 }
    00108
    00109 static void sdmmc_blkdev_req_done(struct sdmmc_request *req)
    00110 {
    00111         struct sdmmc_breq       *breq = req->context;
    00112
    00113         breq->block_req.status = req->status;
    00114         breq->block_req.bytes_xfered = req->bytes_xfered;
    00115
    00116         if (!slist_is_empty(&req->buf_list))
    00117                 slist_move_to_tail(&breq->block_req.buf_list, &req->buf_list);
    00118
    00119         breq->block_req.req_done(breq->block_req.bdev, &breq->block_req);
    00120 }
    00121
    00122 static void sdmmc_blkdev_buf_list_done(struct sdmmc_request *req,
    00123                 struct slist *buf_list)
    00124 {
    00125         struct sdmmc_breq       *breq = req->context;
    00126
    00127         if (breq->block_req.buf_list_done)
    00128                 breq->block_req.buf_list_done(breq->block_req.bdev,
    00129                                 &breq->block_req, buf_list);
    00130         else
    00131                 slist_move_to_tail(&breq->block_req.buf_list, buf_list);
    00132 }
    00133
    00134 static void sdmmc_blkdev_prepare_req(struct block_device *bdev,
    00135                 struct block_request *req,
    00136                 uint32_t lba, uint32_t nr_blocks,
    00137                 enum block_operation operation)
    00138 {
    00139         struct sdmmc_breq       *breq = sdmmc_breq_of(req);
    00140         struct sdmmc_slot       *slot = sdmmc_slot_of(bdev);
    00141         bool                    write;
    00142
    00143         slist_init(&breq->block_req.buf_list);
    00144         breq->block_req.status = -STATUS_IN_PROGRESS;
    00145         breq->block_req.bytes_xfered = 0;
    00146         breq->block_req.req_submit = sdmmc_blkdev_submit_req;
    00147         breq->block_req.req_submit_buf_list = sdmmc_blkdev_submit_buf_list;
    00148
    00149         if (operation == BLK_OP_WRITE)
    00150                 write = true;
    00151         else
    00152                 write = false;
    00153
    00154         sdmmc_req_prep_transfer(slot, &breq->sdmmc_req, lba, nr_blocks, write);
    00155         slist_init(&breq->sdmmc_req.buf_list);
    00156         breq->sdmmc_req.req_started = sdmmc_blkdev_req_started;
    00157         breq->sdmmc_req.req_done = sdmmc_blkdev_req_done;
    00158         breq->sdmmc_req.buf_list_done = sdmmc_blkdev_buf_list_done;
    00159         breq->sdmmc_req.context = breq;
    00160 }
    00161
    00162 static struct block_request *sdmmc_blkdev_alloc_req(struct block_device *bdev)
    00163 {
    00164         struct sdmmc_breq       *req;
    00165
    00166         req = malloc(sizeof(struct sdmmc_breq));
    00167         if (unlikely(!req))
    00168                 return NULL;
    00169         memset(req, 0, sizeof(struct sdmmc_breq));
    00170
    00171         req->block_req.req_submit = sdmmc_blkdev_submit_req;
    00172
    00173         return &req->block_req;
    00174 }
    00175
    00176 static void sdmmc_blkdev_free_req(struct block_device *bdev,
    00177                 struct block_request *req)
    00178 {
    00179         struct sdmmc_breq       *breq = sdmmc_breq_of(req);
    00180
    00181         free(breq);
    00182 }
    00183
    00184 static void sdmmc_blkdev_event(struct sdmmc_slot *slot, void *context)
    00185 {
    00186         struct sdmmc_bdev       *bdev = context;
    00187
    00188         if (sdmmc_slot_is_card_present(slot)) {
    00189                 if (sdmmc_slot_is_card_write_protected(slot))
    00190                         clear_bit(BDEV_WRITEABLE, &bdev->bdev.flags);
    00191                 else
    00192                         set_bit(BDEV_WRITEABLE, &bdev->bdev.flags);
    00193
    00194                 set_bit(BDEV_PRESENT, &bdev->bdev.flags);
    00195                 bdev->bdev.block_size = slot->card.block_size;
    00196                 bdev->bdev.nr_blocks = slot->card.csd.capacity;
    00197         }
    00198         else
    00199                 clear_bit(BDEV_PRESENT, &bdev->bdev.flags);
    00200         bdev->event(&bdev->bdev, bdev->context);
    00201 }
    00202
    00203 static uint32_t sdmmc_blkdev_get_dev_id(struct block_device *bdev)
    00204 {
    00205         struct sdmmc_slot       *slot = sdmmc_slot_of(bdev);
    00206
    00207         return slot->card.cid.serial;
    00208 }
    00209
    00218 struct block_device *sdmmc_blkdev_init_new(struct sdmmc_slot *slot,
    00219                 void (*event)(struct block_device *blkdev, void *context),
    00220                 void *context)
    00221 {
    00222         struct sdmmc_bdev *bdev;
    00223
    00224         bdev = malloc(sizeof(struct sdmmc_bdev));
    00225         if (!bdev)
    00226                 return NULL;
    00227         memset(bdev, 0, sizeof(struct sdmmc_bdev));
    00228
    00229         bdev->bdev.prepare_req = sdmmc_blkdev_prepare_req;
    00230         bdev->bdev.alloc_req = sdmmc_blkdev_alloc_req;
    00231         bdev->bdev.free_req = sdmmc_blkdev_free_req;
    00232         bdev->bdev.get_dev_id = sdmmc_blkdev_get_dev_id;
    00233
    00234         bdev->slot = slot;
    00235         bdev->event = event;
    00236         bdev->context = context;
    00237
    00238         sdmmc_probe_init(slot, sdmmc_blkdev_event, bdev);
    00239
    00240         return &bdev->bdev;
    00241 }
    00242