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