static int blkdev_transfer(uint8_t minor, uint8_t rawflag) { uint8_t partition, n; uint16_t count = 0; /* we trust that blkdev_open() has already verified that this minor number is valid */ blk_op.blkdev = &blkdev_table[minor >> 4]; partition = minor & 0x0F; blk_op.is_user = rawflag; switch(rawflag){ case 0: /* read single 512-byte sector to buffer in kernel memory */ break; case 1: /* read some number of 512-byte sectors directly to user memory */ if (d_blkoff(BLKSHIFT)) return -1; break; #ifdef SWAPDEV case 2: blk_op.swap_page = swappage; break; #endif default: goto xferfail; } /* FIXME: these should go away now but we need to make u_block some kind of raw blkno_t that can be 32bit optionally */ blk_op.nblock = udata.u_nblock; blk_op.lba = udata.u_block; blk_op.addr = udata.u_dptr; if(partition == 0){ /* partition 0 is the whole disk and requires no translation */ if(blk_op.lba >= blk_op.blkdev->drive_lba_count) goto xferfail; }else{ /* partitions 1+ require us to add in an offset */ if(blk_op.lba >= blk_op.blkdev->lba_count[partition-1]) goto xferfail; blk_op.lba += blk_op.blkdev->lba_first[partition-1]; } while(blk_op.nblock){ n = blk_op.blkdev->transfer(); if(n == 0) goto xferfail; blk_op.nblock -= n; count += n; blk_op.addr += n * BLKSIZE; blk_op.lba += n; } return count << BLKSHIFT; /* 10/10, would transfer sectors again */ xferfail: udata.u_error = EIO; return -1; }
static int rd_transfer(bool is_read, uint8_t rawflag) { uint16_t dptr; int ct = 0; int map; const uint8_t *p = kmap; if(rawflag) { p = (const uint8_t *)&udata.u_page; if (d_blkoff(BLKSHIFT)) return -1; } udata.u_block += 2*320; /* ramdisc starts at 320K in */ dptr = (uint16_t)udata.u_dptr; while (ct < udata.u_nblock) { /* Pass the page to map for the data */ map = p[(dptr >> 14)]; rd_memcpy(is_read, map, dptr, udata.u_block); udata.u_block++; ct++; dptr += BLKSIZE; } return ct << BLKSHIFT; }
/* implements both rd_read and rd_write */ int rd_transfer(uint8_t minor, uint8_t rawflag, uint8_t flag) { used(flag); /* check device exists; do not allow writes to ROM */ if (minor == RD_MINOR_ROM && rd_reverse) { udata.u_error = EROFS; return -1; } else { rd_src_address = dev_start[minor]; if (rawflag) { if (d_blkoff(9)) return -1; /* rawflag == 1, userspace transfer */ } rd_dst_userspace = rawflag; rd_dst_address = (uint16_t)udata.u_dptr; rd_src_address += ((uint32_t)udata.u_block) << BLKSHIFT; if (rd_src_address >= dev_limit[minor]) { udata.u_error = EIO; return -1; } } rd_platform_copy(); return rd_cpy_count; }
static int fd_transfer(bool is_read, uint_fast8_t minor, uint_fast8_t rawflag) { uint16_t dptr; uint16_t ct = 0; uint_fast8_t st; fd_page = 0; if(rawflag == 1) { if (d_blkoff(7)) return -1; fd_page = udata.u_page; #ifdef SWAPDEV } else if (rawflag == 2) { /* Swap device special */ fd_page = swappage; /* Acting on this page */ /* * In the z80pack case this is simpler than usual. Be very * careful how you implement the swap device. On most platforms * we have user space in part of the "common" which means you * must be prepared to switch common segment as well during * a swap, or to perform mapping games using the banks */ udata.u_nblock *= (BLKSIZE / 128); /* Limits us to 2^14 blocks (16MB) */ udata.u_block <<= 2; #endif } else { /* rawflag == 0 */ udata.u_nblock = BLKSIZE / 128; /* BLKSIZE bytes implied */ /* Limits us to 2^14 blocks (16MB) */ udata.u_block <<= 2; } /* Read the disk in four sector chunks. FIXME We ought to cache the geometry and just bump sector checking for a wrap. */ fd_dma = (uint16_t)udata.u_dptr; while (ct < udata.u_nblock) { fd_drive = minor; fd_geom(minor, udata.u_block); /* The Z80pack DMA uses the current MMU mappings... beware that * is odd - but most hardware would be PIO (inir/otir etc) anyway */ fd_cmd = 1 - is_read; st = fd_op(); /* Real disks would need retries */ if (st) { kprintf("fd%d: block %d, error %d\n", minor, udata.u_block, st); break; } udata.u_block++; ct++; fd_dma += 128; } return ct << 7; }
static int devfd_transfer(bool is_read, uint8_t is_raw) { int ct = 0; int tries; int blocks = udata.u_nblock; uint16_t lba = udata.u_block; // kprintf("[%s %d @ %x : %d:%x]\n", is_read ? "read" : "write", // blocks, lba, is_raw, udata.u_dptr); // if (!is_read) // return blocks << BLKSHIFT; if (is_raw && d_blkoff(BLKSHIFT)) return -1; fd_select(0); fd765_is_user = is_raw; fd765_buffer = udata.u_dptr; while (blocks != 0) { for (tries = 0; tries < 3; tries ++) { nudge_timer(); if (tries != 0) fd_recalibrate(); fd_seek(lba); fd765_sectors = 10 - fd765_sector; if (fd765_sectors > blocks) fd765_sectors = blocks; if (is_read) fd765_do_read(); else fd765_do_write(); /* Did it work ? */ if ((fd765_status[0] & 0xc0) == 0) break; } if (tries == 3) { kprintf("fd%d: I/O error %d:%d\n", is_read, lba); udata.u_error = EIO; break; } lba += fd765_sectors; blocks -= fd765_sectors; ct += fd765_sectors; } return ct << BLKSHIFT; }
static int hd_transfer(uint8_t minor, bool is_read, uint8_t rawflag) { uint16_t dptr, nb; irqflags_t irq; uint8_t err; if(rawflag == 1 && d_blkoff(9)) return -1; hd_map = rawflag; dptr = (uint16_t)udata.u_dptr; nb = udata.u_nblock; while (udata.u_nblock--) { *disknum = minor; *diskcylh = udata.u_block >> 8; *diskcyll = udata.u_block; *diskcmd = 1; if ((err = *diskstat) != 0) { kprintf("hd%d: disk error %x\n", err); udata.u_error = EIO; return -1; } irq = di(); if (is_read) hd_read_data(dptr); else hd_write_data(dptr); irqrestore(irq); udata.u_block++; dptr += 512; } return nb; }
/* blkdev method: transfer sectors */ static uint16_t sdc_transfer(uint8_t minor, bool is_read, uint8_t rawflag) { uint8_t nb = 0; uint32_t lba; /* holds 32 bit lsn */ uint8_t *ptr = ((uint8_t *)&lba) + 1; /* points to 24 bit lba in blk op */ uint8_t t; /* temporarory sdc status holder */ uint8_t cmd; /* holds SDC command value */ sdc_transfer_function_t fptr; /* holds which xfer routine we want */ if (rawflag == 1 && d_blkoff(9)) return -1; /* pass rawflag to assembler */ sdcpage = rawflag; /* we get 256 bytes per lba in SDC so convert */ udata.u_nblock *= 2; lba = udata.u_block * 2; ptr[0] |= (minor & 0x7f) << 1; /* setup cmd pointer and command value from blk_op */ if (is_read) { cmd = 0x80; fptr = sdc_read_data; } else { cmd = 0xa0; fptr = sdc_write_data; } /* apply our drive value 0 or 1 */ if (minor & 0x80) cmd++; while (udata.u_nblock--) { /* load up registers */ sdc_reg_param1 = ptr[0]; sdc_reg_param2 = ptr[1]; sdc_reg_param3 = ptr[2]; sdc_reg_cmd= cmd; asm("\texg x,x\n"); /* delay 16us minimum */ asm("\texg x,x\n"); /* wait till SDC is ready */ do { t=sdc_reg_stat; if (t & SDC_FAIL) goto fail; } while(!(t & SDC_READY)); /* do our low-level xfer function */ fptr(udata.u_dptr); /* and wait will ready again, and test for failure */ do { t=sdc_reg_stat; if( t & SDC_FAIL ) goto fail; } while (t & SDC_BUSY); /* increment our blk_op values for next 256 bytes sector */ udata.u_dptr += 256; lba++; nb++; } /* Huzzah! success! */ return nb << 8; /* Boo! failure */ fail: sdc_reg_ctl = 0x00; udata.u_error = EIO; return -1; }
static int fd_transfer(uint8_t minor, bool is_read, uint8_t rawflag) { uint16_t nb = 0; int tries; uint8_t err = 0; uint8_t *driveptr = &fd_tab[minor & 1]; irqflags_t irq; if(rawflag == 1 && d_blkoff(BLKSHIFT)) return -1; udata.u_nblock *= 2; if (rawflag == 2) goto bad2; irq = di(); if (fd_selected != minor) { uint8_t err = fd_motor_on(minor|(minor > 1 ? 0: 0x10)); if (err) goto bad; motorct = 150; /* 3 seconds */ } irqrestore(irq); // kprintf("Issue command: %c drive %d block %d for %d\n", "wr"[is_read], minor, udata.u_block, udata.u_nblock); fd_cmd[0] = rawflag; fd_cmd[1] = is_read ? FD_READ : FD_WRITE; /* There are 16 256 byte sectors for DSDD. These are organised so that we switch head then step. Sectors 0-15 (our block 0-7) Track 0, side 0 Sectors 16-31 (our block 8-15) Track 0, side 1 etc */ fd_cmd[2] = udata.u_block / 16; /* Get the track we need */ fd_cmd[3] = ((udata.u_block & 15) << 1); /* 0 - 1 base is corrected in asm */ fd_cmd[4] = is_read ? OPDIR_READ: OPDIR_WRITE; fd_data = (uint16_t)udata.u_dptr; while (udata.u_nblock--) { for (tries = 0; tries < 4 ; tries++) { // kprintf("Sector: %d Head: %d Track %d\n", (fd_cmd[3]&15)+1, fd_cmd[3]>>4, fd_cmd[2]); err = fd_operation(driveptr); if (err == 0) break; if (tries > 1) fd_reset(driveptr); } /* FIXME: should we try the other half and then bale out ? */ if (tries == 3) goto bad; fd_data += 256; fd_cmd[3]++; /* Next sector for next block */ if (fd_cmd[3] == 32) { /* Next track */ fd_cmd[3] = 0; fd_cmd[2]++; } nb++; } return nb << (BLKSHIFT - 1); bad: kprintf("fd%d: error %x\n", minor, err); bad2: udata.u_error = EIO; return -1; }
static int fd_transfer(uint8_t minor, bool is_read, uint8_t rawflag) { int8_t tries; uint8_t err = 0; uint8_t drive = minor & 3; uint8_t trackno, sector; uint8_t large = !(minor & 0x10); const uint8_t *skew = skewtab[large]; /* skew table */ if(rawflag == 2) goto bad2; fd_map = rawflag; if (rawflag && d_blkoff(BLKSHIFT)) return -1; /* Command to go to the controller after any seek is done */ fd_cmd[0] = is_read ? FD_READ : FD_WRITE; /* Control byte: autowait, DD, motor, 5", drive bit */ fd_cmd[1] = 0xE0 | selmap[drive]; if (large) fd_cmd[1] = 0x10; /* turn on 8" bit */ /* Directon of xfer */ fd_cmd[2] = is_read ? OPDIR_READ: OPDIR_WRITE; fd_cmd[5] = 0x10 | delay[drive]; /* * Restore the track register to match this drive */ if (track[drive] != 0xFF) fd_track = track[drive]; else fd_reset(); /* * Begin transfers */ while (udata.u_done < udata.u_nblock) { /* Need to consider SS v DS here */ if (large) { fd_aux = 0x4C | (udata.u_block & 16) ? 2 : 0; trackno = udata.u_block / 32; sector = udata.u_block % 16; } else { trackno = udata.u_block / 20; sector = udata.u_block % 20; if (sector > 9) { sector -= 10; fd_aux = 0x5E; /* side 1 */ } else fd_aux = 0x5C; } /* Buffer */ fd_cmd[3] = ((uint16_t)udata.u_dptr) & 0xFF; fd_cmd[4] = ((uint16_t)udata.u_dptr) >> 8; for (tries = 0; tries < 4 ; tries++) { (void)fd_data; fd_sector = skew[sector]; /* Also makes 1 based */ if (fd_track != trackno) { fd_data = trackno; if (fd_seek()) { fd_reset(); continue; } } /* Do the read or write */ err = fd_operation(); if (err == 0) break; /* Try and recover */ if (tries > 1) fd_reset(); } if (tries == 4) goto bad; udata.u_block++; udata.u_done++; } /* Save the track */ track[drive] = fd_track; return udata.u_done << 9; bad: track[drive] = fd_track; kprintf("fd%d: error %x\n", minor, err); bad2: udata.u_error = EIO; return -1; }