int mcdclose(dev_t dev, int flag, int fmt, struct lwp *l) { struct mcd_softc *sc = device_lookup_private(&mcd_cd, MCDUNIT(dev)); int part = MCDPART(dev); MCD_TRACE("close: partition=%d\n", part); mutex_enter(&sc->sc_lock); switch (fmt) { case S_IFCHR: sc->sc_dk.dk_copenmask &= ~(1 << part); break; case S_IFBLK: sc->sc_dk.dk_bopenmask &= ~(1 << part); break; } sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; if (sc->sc_dk.dk_openmask == 0) { /* XXXX Must wait for I/O to complete! */ #if 0 (void) mcd_setmode(sc, MCD_MD_SLEEP); #endif (void) mcd_setlock(sc, MCD_LK_UNLOCK); } mutex_exit(&sc->sc_lock); return 0; }
void mcdattach(struct device *parent, struct device *self, void *aux) { struct mcd_softc *sc = (void *)self; struct isa_attach_args *ia = aux; bus_space_tag_t iot = ia->ia_iot; bus_space_handle_t ioh; struct mcd_mbox mbx; /* Map i/o space */ if (bus_space_map(iot, ia->ia_io[0].ir_addr, MCD_NPORT, 0, &ioh)) { printf(": can't map i/o space\n"); return; } mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); sc->sc_iot = iot; sc->sc_ioh = ioh; sc->probe = 0; sc->debug = 0; if (!mcd_find(iot, ioh, sc)) { printf(": mcd_find failed\n"); return; } bufq_alloc(&sc->buf_queue, "disksort", BUFQ_SORT_RAWBLOCK); callout_init(&sc->sc_pintr_ch, 0); /* * Initialize and attach the disk structure. */ disk_init(&sc->sc_dk, device_xname(&sc->sc_dev), &mcddkdriver); disk_attach(&sc->sc_dk); printf(": model %s\n", sc->type != 0 ? sc->type : "unknown"); (void) mcd_setlock(sc, MCD_LK_UNLOCK); mbx.cmd.opcode = MCD_CMDCONFIGDRIVE; mbx.cmd.length = sizeof(mbx.cmd.data.config) - 1; mbx.cmd.data.config.subcommand = MCD_CF_IRQENABLE; mbx.cmd.data.config.data1 = 0x01; mbx.res.length = 0; (void) mcd_send(sc, &mbx, 0); mcd_soft_reset(sc); sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq, IST_EDGE, IPL_BIO, mcdintr, sc); }
int mcdopen(dev_t dev, int flag, int fmt, struct lwp *l) { int error, part; struct mcd_softc *sc; sc = device_lookup_private(&mcd_cd, MCDUNIT(dev)); if (sc == NULL) return ENXIO; mutex_enter(&sc->sc_lock); if (sc->sc_dk.dk_openmask != 0) { /* * If any partition is open, but the disk has been invalidated, * disallow further opens. */ if ((sc->flags & MCDF_LOADED) == 0) { error = EIO; goto bad3; } } else { /* * Lock the drawer. This will also notice any pending disk * change or door open indicator and clear the MCDF_LOADED bit * if necessary. */ (void) mcd_setlock(sc, MCD_LK_LOCK); if ((sc->flags & MCDF_LOADED) == 0) { /* Partially reset the state. */ sc->lastmode = MCD_MD_UNKNOWN; sc->lastupc = MCD_UPC_UNKNOWN; sc->flags |= MCDF_LOADED; /* Set the mode, causing the disk to spin up. */ if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0) goto bad2; /* Load the physical device parameters. */ if (mcd_get_parms(sc) != 0) { error = ENXIO; goto bad2; } /* Read the table of contents. */ if ((error = mcd_read_toc(sc)) != 0) goto bad2; /* Fabricate a disk label. */ mcdgetdisklabel(sc); } } part = MCDPART(dev); MCD_TRACE("open: partition=%d disksize=%ld blksize=%d\n", part, sc->disksize, sc->blksize); /* Check that the partition exists. */ if (part != RAW_PART && (part >= sc->sc_dk.dk_label->d_npartitions || sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { error = ENXIO; goto bad; } /* Insure only one open at a time. */ switch (fmt) { case S_IFCHR: sc->sc_dk.dk_copenmask |= (1 << part); break; case S_IFBLK: sc->sc_dk.dk_bopenmask |= (1 << part); break; } sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; mutex_exit(&sc->sc_lock); return 0; bad2: sc->flags &= ~MCDF_LOADED; bad: if (sc->sc_dk.dk_openmask == 0) { #if 0 (void) mcd_setmode(sc, MCD_MD_SLEEP); #endif (void) mcd_setlock(sc, MCD_LK_UNLOCK); } bad3: mutex_exit(&sc->sc_lock); return error; }
int mcdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) { struct mcd_softc *sc = device_lookup_private(&mcd_cd, MCDUNIT(dev)); int error; int part; #ifdef __HAVE_OLD_DISKLABEL struct disklabel newlabel; #endif MCD_TRACE("ioctl: cmd=0x%lx\n", cmd); if ((sc->flags & MCDF_LOADED) == 0) return EIO; error = disk_ioctl(&sc->sc_dk, dev, cmd, addr, flag, l); if (error != EPASSTHROUGH) return error; part = MCDPART(dev); switch (cmd) { case DIOCWDINFO: case DIOCSDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCWDINFO: case ODIOCSDINFO: #endif { struct disklabel *lp; if ((flag & FWRITE) == 0) return EBADF; #ifdef __HAVE_OLD_DISKLABEL if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { memset(&newlabel, 0, sizeof newlabel); memcpy(&newlabel, addr, sizeof (struct olddisklabel)); lp = &newlabel; } else #endif lp = addr; mutex_enter(&sc->sc_lock); sc->flags |= MCDF_LABELLING; error = setdisklabel(sc->sc_dk.dk_label, lp, /*sc->sc_dk.dk_openmask : */0, sc->sc_dk.dk_cpulabel); if (error == 0) { } sc->flags &= ~MCDF_LABELLING; mutex_exit(&sc->sc_lock); return error; } case DIOCWLABEL: return EBADF; case DIOCGDEFLABEL: mcdgetdefaultlabel(sc, addr); return 0; #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDEFLABEL: mcdgetdefaultlabel(sc, &newlabel); if (newlabel.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(addr, &newlabel, sizeof (struct olddisklabel)); return 0; #endif case CDIOCPLAYTRACKS: return mcd_playtracks(sc, addr); case CDIOCPLAYMSF: return mcd_playmsf(sc, addr); case CDIOCPLAYBLOCKS: return mcd_playblocks(sc, addr); case CDIOCREADSUBCHANNEL: { struct cd_sub_channel_info info; error = mcd_read_subchannel(sc, addr, &info); if (error != 0) { struct ioc_read_subchannel *ch = addr; error = copyout(&info, ch->data, ch->data_len); } return error; } case CDIOCREADSUBCHANNEL_BUF: return mcd_read_subchannel(sc, addr, &((struct ioc_read_subchannel_buf *)addr)->info); case CDIOREADTOCHEADER: return mcd_toc_header(sc, addr); case CDIOREADTOCENTRYS: { struct cd_toc_entry entries[MCD_MAXTOCS]; struct ioc_read_toc_entry *te = addr; int count; if (te->data_len > sizeof entries) return EINVAL; error = mcd_toc_entries(sc, te, entries, &count); if (error == 0) /* Copy the data back. */ error = copyout(entries, te->data, min(te->data_len, count * sizeof(struct cd_toc_entry))); return error; } case CDIOREADTOCENTRIES_BUF: { struct ioc_read_toc_entry_buf *te = addr; int count; if (te->req.data_len > sizeof te->entry) return EINVAL; return mcd_toc_entries(sc, &te->req, te->entry, &count); } case CDIOCSETPATCH: case CDIOCGETVOL: case CDIOCSETVOL: case CDIOCSETMONO: case CDIOCSETSTEREO: case CDIOCSETMUTE: case CDIOCSETLEFT: case CDIOCSETRIGHT: return EINVAL; case CDIOCRESUME: return mcd_resume(sc); case CDIOCPAUSE: return mcd_pause(sc); case CDIOCSTART: return EINVAL; case CDIOCSTOP: return mcd_stop(sc); case DIOCEJECT: if (*(int *)addr == 0) { /* * Don't force eject: check that we are the only * partition open. If so, unlock it. */ if ((sc->sc_dk.dk_openmask & ~(1 << part)) == 0 && sc->sc_dk.dk_bopenmask + sc->sc_dk.dk_copenmask == sc->sc_dk.dk_openmask) { error = mcd_setlock(sc, MCD_LK_UNLOCK); if (error) return (error); } else { return (EBUSY); } } /* FALLTHROUGH */ case CDIOCEJECT: /* FALLTHROUGH */ case ODIOCEJECT: return mcd_eject(sc); case CDIOCALLOW: return mcd_setlock(sc, MCD_LK_UNLOCK); case CDIOCPREVENT: return mcd_setlock(sc, MCD_LK_LOCK); case DIOCLOCK: return mcd_setlock(sc, (*(int *)addr) ? MCD_LK_LOCK : MCD_LK_UNLOCK); case CDIOCSETDEBUG: sc->debug = 1; return 0; case CDIOCCLRDEBUG: sc->debug = 0; return 0; case CDIOCRESET: return mcd_hard_reset(sc); default: return ENOTTY; } #ifdef DIAGNOSTIC panic("mcdioctl: impossible"); #endif }