Changeset 0eacc32 in mainline
- Timestamp:
- 2015-04-10T07:06:21Z (10 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 13888eb0
- Parents:
- 07c913b
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/block/ddisk/ddisk.c
r07c913b r0eacc32 37 37 #include <str_error.h> 38 38 #include <ddf/driver.h> 39 #include <ddf/interrupt.h> 39 40 #include <ddf/log.h> 40 41 #include <device/hw_res_parsed.h> … … 50 51 #define DDISK_BLOCK_SIZE 512 51 52 52 static int ddisk_dev_add(ddf_dev_t *dev); 53 static int ddisk_dev_remove(ddf_dev_t *dev); 54 static int ddisk_dev_gone(ddf_dev_t *dev); 55 static int ddisk_fun_online(ddf_fun_t *fun); 56 static int ddisk_fun_offline(ddf_fun_t *fun); 53 #define DDISK_STAT_IRQ_PENDING 0x4 54 #define DDISK_CMD_READ 0x1 55 #define DDISK_CMD_WRITE 0x2 56 #define DDISK_CMD_IRQ_DEASSERT 0x4 57 58 static int ddisk_dev_add(ddf_dev_t *); 59 static int ddisk_dev_remove(ddf_dev_t *); 60 static int ddisk_dev_gone(ddf_dev_t *); 61 static int ddisk_fun_online(ddf_fun_t *); 62 static int ddisk_fun_offline(ddf_fun_t *); 57 63 58 64 static void ddisk_bd_connection(ipc_callid_t, ipc_call_t *, void *); 65 66 static void ddisk_irq_handler(ipc_callid_t, ipc_call_t *, ddf_dev_t *); 59 67 60 68 static driver_ops_t driver_ops = { … … 99 107 typedef struct ddisk_dev { 100 108 fibril_mutex_t lock; 109 fibril_condvar_t io_cv; 110 bool io_busy; 101 111 ddf_dev_t *dev; 102 112 ddisk_res_t ddisk_res; … … 109 119 static int ddisk_bd_open(bd_srvs_t *, bd_srv_t *); 110 120 static int ddisk_bd_close(bd_srv_t *); 111 static int ddisk_bd_read_blocks(bd_srv_t *, uint64_t, size_t, void *, size_t);112 static int ddisk_bd_write_blocks(bd_srv_t *, uint64_t, size_t, const void *,121 static int ddisk_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t); 122 static int ddisk_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, 113 123 size_t); 114 124 static int ddisk_bd_get_block_size(bd_srv_t *, size_t *); … … 124 134 }; 125 135 136 irq_pio_range_t ddisk_irq_pio_ranges[] = { 137 { 138 .base = 0, 139 .size = sizeof(ddisk_regs_t) 140 } 141 }; 142 143 irq_cmd_t ddisk_irq_commands[] = { 144 { 145 .cmd = CMD_PIO_READ_32, 146 .addr = NULL, 147 .dstarg = 1 148 }, 149 { 150 .cmd = CMD_AND, 151 .srcarg = 1, 152 .value = DDISK_STAT_IRQ_PENDING, 153 .dstarg = 2 154 }, 155 { 156 .cmd = CMD_PREDICATE, 157 .srcarg = 2, 158 .value = 2 159 }, 160 { 161 /* Deassert the DMA interrupt. */ 162 .cmd = CMD_PIO_WRITE_32, 163 .value = DDISK_CMD_IRQ_DEASSERT, 164 .addr = NULL 165 }, 166 { 167 .cmd = CMD_ACCEPT 168 } 169 }; 170 171 irq_code_t ddisk_irq_code = { 172 .rangecount = 1, 173 .ranges = ddisk_irq_pio_ranges, 174 .cmdcount = sizeof(ddisk_irq_commands) / sizeof(irq_cmd_t), 175 .cmds = ddisk_irq_commands, 176 }; 177 178 void ddisk_irq_handler(ipc_callid_t iid, ipc_call_t *icall, ddf_dev_t *dev) 179 { 180 ddf_msg(LVL_NOTE, "ddisk_irq_handler(), status=%" PRIx32, 181 (uint32_t) IPC_GET_ARG1(*icall)); 182 183 ddisk_dev_t *ddisk_dev = (ddisk_dev_t *) ddf_dev_data_get(dev); 184 185 fibril_mutex_lock(&ddisk_dev->lock); 186 fibril_condvar_broadcast(&ddisk_dev->io_cv); 187 fibril_mutex_unlock(&ddisk_dev->lock); 188 } 189 126 190 int ddisk_bd_open(bd_srvs_t *bds, bd_srv_t *bd) 127 191 { … … 134 198 } 135 199 136 int 137 ddisk_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, void *buf, 138 size_t size) 139 { 200 static 201 int ddisk_rw_block(ddisk_dev_t *ddisk_dev, bool read, aoff64_t ba, void *buf) 202 { 203 fibril_mutex_lock(&ddisk_dev->lock); 204 205 ddf_msg(LVL_NOTE, "ddisk_rw_block(): read=%d, ba=%" PRId64 ", buf=%p", 206 read, ba, buf); 207 208 if (ba >= ddisk_dev->ddisk_fun->blocks) 209 return ELIMIT; 210 211 while (ddisk_dev->io_busy) 212 fibril_condvar_wait(&ddisk_dev->io_cv, &ddisk_dev->lock); 213 214 ddisk_dev->io_busy = true; 215 216 if (!read) 217 memcpy(ddisk_dev->dma_buffer, buf, DDISK_BLOCK_SIZE); 218 219 pio_write_32(&ddisk_dev->ddisk_regs->dma_buffer, 220 ddisk_dev->dma_buffer_phys); 221 pio_write_32(&ddisk_dev->ddisk_regs->block, (uint32_t) ba); 222 pio_write_32(&ddisk_dev->ddisk_regs->command, 223 read ? DDISK_CMD_READ : DDISK_CMD_WRITE); 224 225 fibril_condvar_wait(&ddisk_dev->io_cv, &ddisk_dev->lock); 226 227 if (read) 228 memcpy(buf, ddisk_dev->dma_buffer, DDISK_BLOCK_SIZE); 229 230 ddisk_dev->io_busy = false; 231 fibril_condvar_signal(&ddisk_dev->io_cv); 232 fibril_mutex_unlock(&ddisk_dev->lock); 233 234 return EOK; 235 } 236 237 static 238 int ddisk_bd_rw_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, void *buf, 239 size_t size, bool is_read) 240 { 241 ddisk_fun_t *ddisk_fun = (ddisk_fun_t *) bd->srvs->sarg; 242 aoff64_t i; 243 int rc; 244 140 245 if (size < cnt * DDISK_BLOCK_SIZE) 141 246 return EINVAL; 142 247 143 return ENOTSUP; 144 } 145 146 int ddisk_bd_write_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, 248 for (i = 0; i < cnt; i++) { 249 rc = ddisk_rw_block(ddisk_fun->ddisk_dev, is_read, ba + i, 250 buf + i * DDISK_BLOCK_SIZE); 251 if (rc != EOK) 252 return rc; 253 } 254 255 return EOK; 256 } 257 258 int ddisk_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, void *buf, 259 size_t size) 260 { 261 return ddisk_bd_rw_blocks(bd, ba, cnt, buf, size, true); 262 } 263 264 int ddisk_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, 147 265 const void *buf, size_t size) 148 266 { 149 if (size < cnt * DDISK_BLOCK_SIZE) 150 return EINVAL; 151 152 return ENOTSUP; 267 return ddisk_bd_rw_blocks(bd, ba, cnt, (void *) buf, size, false); 153 268 } 154 269 … … 332 447 333 448 fibril_mutex_initialize(&ddisk_dev->lock); 449 fibril_condvar_initialize(&ddisk_dev->io_cv); 450 ddisk_dev->io_busy = false; 334 451 ddisk_dev->dev = dev; 335 452 ddisk_dev->ddisk_res = res; … … 374 491 } 375 492 376 ddf_msg(LVL_NOTE, "Device at %p with %d blocks (%dB) using interrupt %d", 493 /* 494 * Register IRQ handler. 495 */ 496 ddisk_regs_t *res_phys = (ddisk_regs_t *) res.base; 497 ddisk_irq_pio_ranges[0].base = res.base; 498 ddisk_irq_commands[0].addr = (void *) &res_phys->status; 499 ddisk_irq_commands[3].addr = (void *) &res_phys->command; 500 rc = register_interrupt_handler(dev, ddisk_dev->ddisk_res.irq, 501 ddisk_irq_handler, &ddisk_irq_code); 502 if (rc != EOK) { 503 ddf_msg(LVL_ERROR, "Failed to register interrupt handler."); 504 goto error; 505 } 506 507 /* 508 * Success, report what we have found. 509 */ 510 ddf_msg(LVL_NOTE, 511 "Device at %p with %zu blocks (%zuB) using interrupt %d", 377 512 (void *) ddisk_dev->ddisk_res.base, ddisk_dev->ddisk_fun->blocks, 378 ddisk_dev->ddisk_fun->blocks * DDISK_BLOCK_SIZE, ddisk_dev->ddisk_res.irq); 513 ddisk_dev->ddisk_fun->blocks * DDISK_BLOCK_SIZE, 514 ddisk_dev->ddisk_res.irq); 379 515 380 516 return EOK;
Note:
See TracChangeset
for help on using the changeset viewer.