+ dp = &drv_table[drv];
+ track = (uint16_t)(msg[TRK+1] << 8) + msg[TRK];
+ sec = (uint16_t)(msg[SEC+1] << 8) + msg[SEC];
+ secs = msg[CNT];
+ addr = ((uint32_t)msg[ADDR+2] << 16) + ((uint16_t)msg[ADDR+1] << 8) + msg[ADDR];
+
+ if (dp->img_name == NULL) {
+ /* no media */
+ return msg_cpm_result(subf, 0x06, res);
+ }
+
+ /* TODO: tracks per sector from dpb */
+ pos = (track * 8UL + sec) * CONFIG_CPM_BLOCK_SIZE;
+
+ drv_debug(MIDDLE, PSTR(" T:%4d, S:%2d, cnt:%2d, lba: %.8lx, addr: %.5lx"),
+ track, sec, secs, pos, addr);
+
+ if (dowrite && dp->opt & DRV_OPT_RO) {
+ return msg_cpm_result(subf, 0x05, res);
+ }
+
+
+ if (pos + secs * CONFIG_CPM_BLOCK_SIZE > CONFIG_CPM_DISKSIZE) {
+ drv_debug(MIDDLE, PSTR(" access > DISKSIZE:%.8lx!"),
+ CONFIG_CPM_DISKSIZE);
+ return msg_cpm_result(subf, 0x04, res);
+ }
+
+ res = f_lseek(&dp->fd, pos);
+
+ while (!res && secs--) {
+ unsigned int brw;
+ if (dowrite) {
+ if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+ buserr = 1;
+ break;
+ } else {
+ z80_read_block(disk_buffer, addr, CONFIG_CPM_BLOCK_SIZE);
+ z80_bus_cmd(Release);
+ }
+ res = f_write(&dp->fd, disk_buffer, CONFIG_CPM_BLOCK_SIZE, &brw);
+ } else {
+ res = f_read(&dp->fd, disk_buffer, CONFIG_CPM_BLOCK_SIZE, &brw);
+ if (res == FR_OK) {
+ if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+ buserr = 1;
+ break;
+ } else {
+ z80_write_block(disk_buffer, addr, CONFIG_CPM_BLOCK_SIZE);
+ z80_bus_cmd(Release);
+ }
+ }
+ }
+ if (brw != CONFIG_CPM_BLOCK_SIZE) {
+ drv_debug(MIDDLE, PSTR(" short rd/wr: res: %d, brw: %u"),
+ res, brw);
+ res = 64;
+ }
+ addr += CONFIG_CPM_BLOCK_SIZE;
+ }
+
+ if (dowrite && !res) {
+ dp->flags |= DRV_FLG_DIRTY;
+ bg_setstat(handle_cpm_drv_to, 1);
+ }
+
+ if (buserr) {
+ /* Bus timeout. how can this happen? */
+ rc = 0x03;
+ }
+
+ /* send result*/
+ msg_cpm_result(subf, rc, res);