int fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) { struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); struct fdformat_parms *form_parms; struct fdformat_cmd *form_cmd; struct ne7_fd_formb *fd_formb; struct disklabel buffer; int error; unsigned int scratch; int il[FD_MAX_NSEC + 1]; int i, j; #ifdef __HAVE_OLD_DISKLABEL struct disklabel newlabel; #endif switch (cmd) { case DIOCGDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDINFO: #endif memset(&buffer, 0, sizeof(buffer)); buffer.d_secpercyl = fd->sc_type->seccyl; buffer.d_type = DTYPE_FLOPPY; buffer.d_secsize = FDC_BSIZE; if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL) return EINVAL; #ifdef __HAVE_OLD_DISKLABEL if (cmd == ODIOCGDINFO) { if (buffer.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(addr, &buffer, sizeof (struct olddisklabel)); } else #endif *(struct disklabel *)addr = buffer; return 0; case DIOCWLABEL: if ((flag & FWRITE) == 0) return EBADF; /* XXX do something */ return 0; case DIOCWDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCWDINFO: #endif { struct disklabel *lp; if ((flag & FWRITE) == 0) return EBADF; #ifdef __HAVE_OLD_DISKLABEL if (cmd == ODIOCWDINFO) { memset(&newlabel, 0, sizeof newlabel); memcpy(&newlabel, addr, sizeof (struct olddisklabel)); lp = &newlabel; } else #endif lp = (struct disklabel *)addr; error = setdisklabel(&buffer, lp, 0, NULL); if (error) return error; error = writedisklabel(dev, fdstrategy, &buffer, NULL); return error; } case FDIOCGETFORMAT: form_parms = (struct fdformat_parms *)addr; form_parms->fdformat_version = FDFORMAT_VERSION; form_parms->nbps = 128 * (1 << fd->sc_type->secsize); form_parms->ncyl = fd->sc_type->cyls; form_parms->nspt = fd->sc_type->sectrac; form_parms->ntrk = fd->sc_type->heads; form_parms->stepspercyl = fd->sc_type->step; form_parms->gaplen = fd->sc_type->gap2; form_parms->fillbyte = fd->sc_type->fillbyte; form_parms->interleave = fd->sc_type->interleave; switch (fd->sc_type->rate) { case FDC_500KBPS: form_parms->xfer_rate = 500 * 1024; break; case FDC_300KBPS: form_parms->xfer_rate = 300 * 1024; break; case FDC_250KBPS: form_parms->xfer_rate = 250 * 1024; break; default: return EINVAL; } return 0; case FDIOCSETFORMAT: if((flag & FWRITE) == 0) return EBADF; /* must be opened for writing */ form_parms = (struct fdformat_parms *)addr; if (form_parms->fdformat_version != FDFORMAT_VERSION) return EINVAL; /* wrong version of formatting prog */ scratch = form_parms->nbps >> 7; if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 || scratch & ~(1 << (ffs(scratch)-1))) /* not a power-of-two multiple of 128 */ return EINVAL; switch (form_parms->xfer_rate) { case 500 * 1024: fd->sc_type->rate = FDC_500KBPS; break; case 300 * 1024: fd->sc_type->rate = FDC_300KBPS; break; case 250 * 1024: fd->sc_type->rate = FDC_250KBPS; break; default: return EINVAL; } if (form_parms->nspt > FD_MAX_NSEC || form_parms->fillbyte > 0xff || form_parms->interleave > 0xff) return EINVAL; fd->sc_type->sectrac = form_parms->nspt; if (form_parms->ntrk != 2 && form_parms->ntrk != 1) return EINVAL; fd->sc_type->heads = form_parms->ntrk; fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk; fd->sc_type->secsize = ffs(scratch)-1; fd->sc_type->gap2 = form_parms->gaplen; fd->sc_type->cyls = form_parms->ncyl; fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl * form_parms->nbps / DEV_BSIZE; fd->sc_type->step = form_parms->stepspercyl; fd->sc_type->fillbyte = form_parms->fillbyte; fd->sc_type->interleave = form_parms->interleave; return 0; case FDIOCFORMAT_TRACK: if((flag & FWRITE) == 0) return EBADF; /* must be opened for writing */ form_cmd = (struct fdformat_cmd *)addr; if (form_cmd->formatcmd_version != FDFORMAT_VERSION) return EINVAL; /* wrong version of formatting prog */ if (form_cmd->head >= fd->sc_type->heads || form_cmd->cylinder >= fd->sc_type->cyls) { return EINVAL; } fd_formb = malloc(sizeof(struct ne7_fd_formb), M_TEMP, M_NOWAIT); if (fd_formb == 0) return ENOMEM; fd_formb->head = form_cmd->head; fd_formb->cyl = form_cmd->cylinder; fd_formb->transfer_rate = fd->sc_type->rate; fd_formb->fd_formb_secshift = fd->sc_type->secsize; fd_formb->fd_formb_nsecs = fd->sc_type->sectrac; fd_formb->fd_formb_gaplen = fd->sc_type->gap2; fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte; memset(il, 0, sizeof il); for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) { while (il[(j%fd_formb->fd_formb_nsecs)+1]) j++; il[(j%fd_formb->fd_formb_nsecs)+1] = i; j += fd->sc_type->interleave; } for (i = 0; i < fd_formb->fd_formb_nsecs; i++) { fd_formb->fd_formb_cylno(i) = form_cmd->cylinder; fd_formb->fd_formb_headno(i) = form_cmd->head; fd_formb->fd_formb_secno(i) = il[i+1]; fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize; } error = fdformat(dev, fd_formb, l); free(fd_formb, M_TEMP); return error; case FDIOCGETOPTS: /* get drive options */ *(int *)addr = fd->sc_opts; return 0; case FDIOCSETOPTS: /* set drive options */ fd->sc_opts = *(int *)addr; return 0; default: return ENOTTY; } #ifdef DIAGNOSTIC panic("fdioctl: impossible"); #endif }
int fdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; struct disklabel *lp; int error; switch (cmd) { case MTIOCTOP: if (((struct mtop *)addr)->mt_op != MTOFFL) return EIO; return (0); case DIOCRLDINFO: lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); fdgetdisklabel(dev, fd, lp, 0); bcopy(lp, fd->sc_dk.dk_label, sizeof(*lp)); free(lp, M_TEMP); return 0; case DIOCGPDINFO: fdgetdisklabel(dev, fd, (struct disklabel *)addr, 1); return 0; case DIOCGDINFO: *(struct disklabel *)addr = *(fd->sc_dk.dk_label); return 0; case DIOCGPART: ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label; ((struct partinfo *)addr)->part = &fd->sc_dk.dk_label->d_partitions[FDPART(dev)]; return 0; case DIOCWDINFO: case DIOCSDINFO: if ((flag & FWRITE) == 0) return EBADF; error = setdisklabel(fd->sc_dk.dk_label, (struct disklabel *)addr, 0); if (error == 0) { if (cmd == DIOCWDINFO) error = writedisklabel(DISKLABELDEV(dev), fdstrategy, fd->sc_dk.dk_label); } return error; case FD_FORM: if((flag & FWRITE) == 0) return EBADF; /* must be opened for writing */ else if(((struct fd_formb *)addr)->format_version != FD_FORMAT_VERSION) return EINVAL; /* wrong version of formatting prog */ else return fdformat(dev, (struct fd_formb *)addr, p); break; case FD_GTYPE: /* get drive type */ *(struct fd_type *)addr = *fd->sc_type; return 0; case FD_GOPTS: /* get drive options */ *(int *)addr = fd->sc_opts; return 0; case FD_SOPTS: /* set drive options */ fd->sc_opts = *(int *)addr; return 0; default: return ENOTTY; } #ifdef DIAGNOSTIC panic("fdioctl: impossible"); #endif }